File: README

File
README
Path: | railties/README
Modified: | Sun Mar 02 11:09:10 -0700 2008

Welcome to Rails

Rails is a web-application and persistence framework that includes everything needed to create database-backed web-applications according to the Model-View-Control pattern of separation. This pattern splits the view (also called the presentation) into "dumb" templates that are primarily responsible for inserting pre-built data in between HTML tags. The model contains the "smart" domain objects (such as Account, Product, Person, Post) that holds all the business logic and knows how to persist themselves to a database. The controller handles the incoming requests (such as Save New Account, Update Product, Show Post) by manipulating the model and directing data to the view.

In Rails, the model is handled by what‘s called an object-relational mapping layer entitled Active Record. This layer allows you to present the data from database rows as objects and embellish these data objects with business logic methods. You can read more about Active Record in files/activerecord/README.html.

The controller and view are handled by the Action Pack, which handles both layers by its two parts: Action View and Action Controller. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between the Active Record and Action Pack that is much more separate. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in files/actionpack/README.html.

Getting Started

  1. At the command prompt, start a new Rails application using the rails command and your application name. Ex: rails myapp (If you‘ve downloaded Rails in a complete tgz or zip, this step is already done)
  2. Change directory into myapp and start the web server: script/server (run with —help for options)
  3. Go to localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
  4. Follow the guidelines to start developing your application

Web Servers

By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise Rails will use WEBrick, the webserver that ships with Ruby. When you run script/server, Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures that you can always get up and running quickly.

Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is suitable for development and deployment of Rails applications. If you have Ruby Gems installed, getting up and running with mongrel is as easy as: gem install mongrel. More info at: mongrel.rubyforge.org

If Mongrel is not installed, Rails will look for lighttpd. It‘s considerably faster than Mongrel and WEBrick and also suited for production use, but requires additional installation and currently only works well on OS X/Unix (Windows users are encouraged to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from www.lighttpd.net.

And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not for production.

But of course its also possible to run Rails on any platform that supports FCGI. Apache, LiteSpeed, IIS are just a few. For more information on FCGI, please visit: wiki.rubyonrails.com/rails/pages/FastCGI

Debugging Rails

Sometimes your application goes wrong. Fortunately there are a lot of tools that will help you debug it and get it back on the rails.

First area to check is the application log files. Have "tail -f" commands running on the server.log and development.log. Rails will automatically display debugging and runtime information to these files. Debugging info will also be shown in the browser on requests from 127.0.0.1.

You can also log your own messages directly into the log file from your code using the Ruby logger class from inside your controllers. Example:

  class WeblogController < ActionController::Base
    def destroy
      @weblog = Weblog.find(params[:id])
      @weblog.destroy
      logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
    end
  end

The result will be a message in your log file along the lines of:

  Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1

More information on how to use the logger is at www.ruby-doc.org/core/

Also, Ruby documentation can be found at www.ruby-lang.org/ including:

  • The Learning Ruby (Pickaxe) Book: www.ruby-doc.org/docs/ProgrammingRuby/
  • Learn to Program: pine.fm/LearnToProgram/ (a beginners guide)

These two online (and free) books will bring you up to speed on the Ruby language and also on programming in general.

Debugger

Debugger support is available through the debugger command when you start your Mongrel or Webrick server with —debugger. This means that you can break out of execution at any point in the code, investigate and change the model, AND then resume execution! Example:

  class WeblogController < ActionController::Base
    def index
      @posts = Post.find(:all)
      debugger
    end
  end

So the controller will accept the action, run the first line, then present you with a IRB prompt in the server window. Here you can do things like:

  >> @posts.inspect
  => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
       #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
  >> @posts.first.title = "hello from a debugger"
  => "hello from a debugger"

…and even better is that you can examine how your runtime objects actually work:

  >> f = @posts.first
  => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
  >> f.
  Display all 152 possibilities? (y or n)

Finally, when you‘re ready to resume execution, you enter "cont"

Console

You can interact with the domain model by starting the console through script/console. Here you‘ll have all parts of the application configured, just like it is when the application is running. You can inspect domain models, change values, and save to the database. Starting the script without arguments will launch it in the development environment. Passing an argument will specify a different environment, like script/console production.

To reload your controllers and models after launching the console run reload!

Description of Contents

app

  Holds all the code that's specific to this particular application.

app/controllers

  Holds controllers that should be named like weblogs_controller.rb for
  automated URL mapping. All controllers should descend from ApplicationController
  which itself descends from ActionController::Base.

app/models

  Holds models that should be named like post.rb.
  Most models will descend from ActiveRecord::Base.

app/views

  Holds the template files for the view that should be named like
  weblogs/index.erb for the WeblogsController#index action. All views use eRuby
  syntax.

app/views/layouts

  Holds the template files for layouts to be used with views. This models the common
  header/footer method of wrapping views. In your views, define a layout using the
  <tt>layout :default</tt> and create a file named default.erb. Inside default.erb,
  call <% yield %> to render the view using this layout.

app/helpers

  Holds view helpers that should be named like weblogs_helper.rb. These are generated
  for you automatically when using script/generate for controllers. Helpers can be used to
  wrap functionality for your views into methods.

config

  Configuration files for the Rails environment, the routing map, the database, and other dependencies.

db

  Contains the database schema in schema.rb.  db/migrate contains all
  the sequence of Migrations for your schema.

doc

  This directory is where your application documentation will be stored when generated
  using <tt>rake doc:app</tt>

lib

  Application specific libraries. Basically, any kind of custom code that doesn't
  belong under controllers, models, or helpers. This directory is in the load path.

public

  The directory available for the web server. Contains subdirectories for images, stylesheets,
  and javascripts. Also contains the dispatchers and the default HTML files. This should be
  set as the DOCUMENT_ROOT of your web server.

script

  Helper scripts for automation and generation.

test

  Unit and functional tests along with fixtures. When using the script/generate scripts, template
  test files will be generated for you and placed in this directory.

vendor

  External libraries that the application depends on. Also includes the plugins subdirectory.
  This directory is in the load path.


File: MIT-LICENSE

File
MIT-LICENSE
Path: | railties/MIT-LICENSE
Modified: | Sun Mar 02 11:09:10 -0700 2008

Copyright (c) 2004-2007 David Heinemeier Hansson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


File: README

File
README
Path: | actionmailer/README
Modified: | Sun Mar 02 11:09:06 -0700 2008

Action Mailer — Easy email delivery and testing

Action Mailer is a framework for designing email-service layers. These layers are used to consolidate code for sending out forgotten passwords, welcome wishes on signup, invoices for billing, and any other use case that requires a written notification to either a person or another system.

Additionally, an Action Mailer class can be used to process incoming email, such as allowing a weblog to accept new posts from an email (which could even have been sent from a phone).

Sending emails

The framework works by setting up all the email details, except the body, in methods on the service layer. Subject, recipients, sender, and timestamp are all set up this way. An example of such a method:

  def signed_up(recipient)
    recipients recipient
    subject    "[Signed up] Welcome #{recipient}"
    from       "system@loudthinking.com"

    body(:recipient => recipient)
  end

The body of the email is created by using an Action View template (regular ERb) that has the content of the body hash parameter available as instance variables. So the corresponding body template for the method above could look like this:

  Hello there,

  Mr. <%= @recipient %>

And if the recipient was given as "david@loudthinking.com", the email generated would look like this:

  Date: Sun, 12 Dec 2004 00:00:00 +0100
  From: system@loudthinking.com
  To: david@loudthinking.com
  Subject: [Signed up] Welcome david@loudthinking.com

  Hello there,

  Mr. david@loudthinking.com

You never actually call the instance methods like signed_up directly. Instead, you call class methods like deliver_* and create_* that are automatically created for each instance method. So if the signed_up method sat on ApplicationMailer, it would look like this:

  ApplicationMailer.create_signed_up("david@loudthinking.com")  # => tmail object for testing
  ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email
  ApplicationMailer.new.signed_up("david@loudthinking.com")     # won't work!

Receiving emails

To receive emails, you need to implement a public instance method called receive that takes a tmail object as its single parameter. The Action Mailer framework has a corresponding class method, which is also called receive, that accepts a raw, unprocessed email as a string, which it then turns into the tmail object and calls the receive instance method.

Example:

  class Mailman < ActionMailer::Base
    def receive(email)
      page = Page.find_by_address(email.to.first)
      page.emails.create(
        :subject => email.subject, :body => email.body
      )

      if email.has_attachments?
        for attachment in email.attachments
          page.attachments.create({
            :file => attachment, :description => email.subject
          })
        end
      end
    end
  end

This Mailman can be the target for Postfix. In Rails, you would use the runner like this:

  ./script/runner 'Mailman.receive(STDIN.read)'

Configuration

The Base class has the full list of configuration options. Here‘s an example:

ActionMailer::Base.smtp_settings = {

  :address=>'smtp.yourserver.com',    # default: localhost
  :port=>'25',                        # default: 25
  :user_name=>'user',
  :password=>'pass',
  :authentication=>:plain             # :plain, :login or :cram_md5

}

Dependencies

Action Mailer requires that the Action Pack is either available to be required immediately or is accessible as a GEM.

Bundled software

  • tmail 0.10.8 by Minero Aoki released under LGPL Read more on i.loveruby.net/en/prog/tmail.html
  • Text::Format 0.63 by Austin Ziegler released under OpenSource Read more on www.halostatue.ca/ruby/Text__Format.html

Download

The latest version of Action Mailer can be found at

  • rubyforge.org/project/showfiles.php?group_id=361

Documentation can be found at

  • actionmailer.rubyonrails.org

Installation

You can install Action Mailer with the following command.

  % [sudo] ruby install.rb

from its distribution directory.

License

Action Mailer is released under the MIT license.

Support

The Action Mailer homepage is www.rubyonrails.org. You can find the Action Mailer RubyForge page at rubyforge.org/projects/actionmailer. And as Jim from Rake says:

   Feel free to submit commits or feature requests.  If you send a patch,
   remember to update the corresponding unit tests.  If fact, I prefer
   new feature to be submitted in the form of new unit tests.


Class: ActionMailer::Base

Class
ActionMailer::Base
In: | actionmailer/lib/action_mailer/base.rb
Parent: | Object

ActionMailer allows you to send email from your application using a mailer model and views.

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.

  • recipients - Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the To: header.
  • subject - The subject of your email. Sets the Subject: header.
  • from - Who the email you are sending is from. Sets the From: header.
  • cc - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the Cc: header.
  • bcc - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the Bcc header.
  • sent_on - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
  • content_type - Specify the content type of the message. Defaults to text/plain.
  • headers - Specify additional headers to be set for the message, e.g. headers ‘X-Mail-Count’ => 107370.

The body 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, body "account" => recipient would result in an instance variable @account with the value of recipient 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 .erb file with the same name as the method in your mailer model. For example, in the mailer defined above, the template at app/views/notifier/signup_notification.erb 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.

You can even use Action Pack helpers in these views. For example:

  You got a new note!
  <%= truncate(note.body, 25) %>

Generating URLs for mailer views

If your view includes URLs from the application, you need to use url_for in the mailing method instead of the view. Unlike controllers from Action Pack, the mailer instance doesn‘t have any context about the incoming request. That‘s why you need to jump this little hoop and supply all the details needed for the URL. Example:

   def signup_notification(recipient)
     recipients recipient.email_address_with_name
     from       "system@example.com"
     subject    "New account information"
     body       :account => recipient,
                :home_page => url_for(:host => "example.com", :controller => "welcome", :action => "greeting")
   end

You can now access @home_page in the template and get example.com/welcome/greeting.

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 deliver_ followed by the name of the mailer method that you would like to deliver. The signup_notification method defined above is delivered by invoking Notifier.deliver_signup_notification.

HTML email

To send mail as HTML, make sure your view (the .erb 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
      from       "system@example.com"
      content_type "text/html"   #    Here's where the magic happens
    end
  end

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"
      from            "system@example.com"

      part :content_type => "text/html",
        :body => render_message("signup-as-html", :account => recipient)

      part "text/plain" do |p|
        p.body = render_message("signup-as-plain", :account => recipient)
        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.erb
  • signup_notification.text.html.erb
  • signup_notification.text.xml.builder
  • signup_notification.text.x-yaml.erb

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
      subject         "New account information"
      from            "system@example.com"

      attachment :content_type => "image/jpeg",
        :body => File.read("an-image.jpg")

      attachment "application/pdf" do |a|
        a.body = generate_your_pdf_here()
      end
    end
  end

Configuration options

These options are specified on the class level, like ActionMailer::Base.template_root = "/my/templates"

  • template_root - template root determines the base from which template references will be made.
  • logger - the logger is used for generating information on the mailing run if available. Can be set to nil for no logging. Compatible with both Ruby‘s own Logger and Log4r loggers.
  • smtp_settings - Allows detailed configuration for :smtp delivery method:
    • :address Allows you to use a remote mail server. Just change it from its default "localhost" setting.
    • :port On the off chance that your mail server doesn‘t run on port 25, you can change it.
    • :domain If you need to specify a HELO domain, you can do it here.
    • :user_name If your mail server requires authentication, set the username in this setting.
    • :password If your mail server requires authentication, set the password in this setting.
    • :authentication If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of :plain, :login, :cram_md5
  • sendmail_settings - Allows you to override options for the :sendmail delivery method
    • :location The location of the sendmail executable, defaults to "/usr/sbin/sendmail"
    • :arguments The command line arguments
  • raise_delivery_errors - whether or not errors should be raised if the email fails to be delivered.
  • delivery_method - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test.
  • perform_deliveries - Determines whether deliver_* methods are actually carried out. By default they are, but this can be turned off to help functional testing.
  • deliveries - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.
  • default_charset - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also pick a different charset from inside a method with @charset.
  • default_content_type - The default content type used for the main part of the message. Defaults to "text/plain". You can also pick a different content type from inside a method with @content_type.
  • default_mime_version - The default mime version used for the message. Defaults to "1.0". You can also pick a different value from inside a method with @mime_version.
  • default_implicit_parts_order - When a message is built implicitly (i.e. multiple parts are assembled from templates which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client and appear last in the mime encoded message. You can also pick a different order from inside a method with @implicit_parts_order.
Methods
  • controller_name
  • controller_path
  • deliver
  • deliver!
  • mailer_name
  • mailer_name
  • mailer_name=
  • receive
  • register_template_extension
Included Modules
  • AdvAttrAccessor
  • PartContainer
  • ActionController::UrlWriter
Attributes
[R] | mail | The mail object instance referenced by this mailer.
[W] | mailer_name |
Public Class methods
deliver(mail)

Deliver the given mail object directly. This can be used to deliver a preconstructed mail object, like:

  email = MyMailer.create_some_mail(parameters)
  email.set_some_obscure_header "frobnicate"
  MyMailer.deliver(email)

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 382
382:       def deliver(mail)
383:         new.deliver!(mail)
384:       end
mailer_name()

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 341
341:       def mailer_name
342:         @mailer_name ||= name.underscore
343:       end
receive(raw_email)

Receives a raw email, parses it into an email object, decodes it, instantiates a new mailer, and passes the email object to the mailer object‘s receive method. If you want your mailer to be able to process incoming messages, you‘ll need to implement a receive method that accepts the email object as a parameter:

  class MyMailer < ActionMailer::Base
    def receive(mail)
      ...
    end
  end

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 369
369:       def receive(raw_email)
370:         logger.info "Received mail:\n #{raw_email}" unless logger.nil?
371:         mail = TMail::Mail.parse(raw_email)
372:         mail.base64_decode
373:         new.receive(mail)
374:       end
register_template_extension(extension)

Register a template extension so mailer templates written in a templating language other than rhtml or rxml are supported. To use this, include in your template-language plugin‘s init code or on a per-application basis, this can be invoked from config/environment.rb:

  ActionMailer::Base.register_template_extension('haml')

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 393
393:       def register_template_extension(extension)
394:         template_extensions << extension
395:       end
Public Instance methods
controller_name(value = nil)

Alias for mailer_name

controller_path(value = nil)

Alias for mailer_name

deliver!(mail = @mail)

Delivers a TMail::Mail object. By default, it delivers the cached mail object (from the create! method). If no cached mail object exists, and no alternate has been given as the parameter, this will fail.

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 464
464:     def deliver!(mail = @mail)
465:       raise "no mail object available for delivery!" unless mail
466:       logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
467:
468:       begin
469:         __send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
470:       rescue Exception => e  # Net::SMTP errors or sendmail pipe errors
471:         raise e if raise_delivery_errors
472:       end
473:
474:       return mail
475:     end
mailer_name(value = nil)

Override the mailer name, which defaults to an inflected version of the mailer‘s class name. If you want to use a template in a non-standard location, you can use this to specify that location.

This method is also aliased as controller_name controller_path

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 323
323:     def mailer_name(value = nil)
324:       if value
325:         self.mailer_name = value
326:       else
327:         self.class.mailer_name
328:       end
329:     end
mailer_name=(value)

[ show source ]

     # File actionmailer/lib/action_mailer/base.rb, line 331
331:     def mailer_name=(value)
332:       self.class.mailer_name = value
333:     end


File: base.rb

File
base.rb
Path: | actionmailer/lib/action_mailer/base.rb
Modified: | Sun Mar 02 11:09:06 -0700 2008

Required Files
  • action_mailer/adv_attr_accessor
  • action_mailer/part
  • action_mailer/part_container
  • action_mailer/utils
  • tmail/net


File: CHANGELOG

File
CHANGELOG
Path: | actionmailer/CHANGELOG
Modified: | Sun Mar 02 11:09:06 -0700 2008

*2.0.2* (December 16th, 2007)

  • Included in Rails 2.0.2

*2.0.1* (December 7th, 2007)

  • Update ActionMailer so it treats ActionView the same way that ActionController does. Closes 10244 [rick]
    • Pass the template_root as an array as ActionView‘s view_path
    • Request templates with the "#{mailer_name}/#{action}" as opposed to just "#{action}"
  • Fixed that partials would be broken when using text.plain.erb as the extension 10130 [java]
  • Update README to use new smtp settings configuration API. Closes 10060 [psq]
  • Allow ActionMailer subclasses to individually set their delivery method (so two subclasses can have different delivery methods) 10033 [zdennis]
  • Update TMail to v1.1.0. Use an updated version of TMail if available. [mikel]
  • Introduce a new base test class for testing Mailers. ActionMailer::TestCase [Koz]
  • Fix silent failure of rxml templates. 9879 [jstewart]
  • Fix attachment decoding when using the TMail C extension. 7861 [orangechicken]
  • Increase mail delivery test coverage. 8692 [Kamal Fariz Mahyuddin]
  • Register alternative template engines using ActionMailer::Base.register_template_extension(‘haml’). 7534 [cwd, Josh Peek]
  • Only load ActionController::UrlWriter if ActionController is present [Rick Olson]
  • Make sure parsed emails recognized attachments nested inside multipart parts. 6714 [Jamis Buck]
  • Allow mailer actions named send by using send internally. 6467 [iGEL]
  • Add assert_emails and assert_no_emails to test the number of emails delivered. 6479 [Jonathan Viney]
      # Assert total number of emails delivered:
  assert_emails 0
  ContactMailer.deliver_contact
  assert_emails 1

  # Assert number of emails delivered within a block:
  assert_emails 1 do
    post :signup, :name => 'Jonathan'
  end

*1.3.3* (March 12th, 2007)

  • Depend on Action Pack 1.13.3

*1.3.2* (February 5th, 2007)

  • Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Koz]

*1.3.1* (January 16th, 2007)

  • Depend on Action Pack 1.13.1

*1.3.0* (January 16th, 2007)

  • Make mime version default to 1.0. closes 2323 [ror@andreas-s.net]
  • Make sure quoted-printable text is decoded correctly when only portions of the text are encoded. closes 3154. [jon@siliconcircus.com]
  • Make sure DOS newlines in quoted-printable text are normalized to unix newlines before unquoting. closes 4166 and 4452. [Jamis Buck]
  • Fixed that iconv decoding should catch InvalidEncoding 3153 [jon@siliconcircus.com]
  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Automatically included ActionController::UrlWriter, such that URL generation can happen within ActionMailer controllers. [DHH]
  • Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
  • Mailer template root applies to a class and its subclasses rather than acting globally. 5555 [somekool@gmail.com]
  • Resolve action naming collision. 5520 [ssinghi@kreeti.com]
  • ActionMailer::Base documentation rewrite. Closes 4991 [Kevin Clark, Marcel Molina Jr.]
  • Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Correct spurious documentation example code which results in a SyntaxError. [Marcel Molina Jr.]

*1.2.1* (April 6th, 2006)

  • Be part of Rails 1.1.1

*1.2.0* (March 27th, 2006)

  • Nil charset caused subject line to be improperly quoted in implicitly multipart messages 2662 [ehalvorsen+rails@runbox.com]
  • Parse content-type apart before using it so that sub-parts of the header can be set correctly 2918 [Jamis Buck]
  • Make custom headers work in subparts 4034 [elan@bluemandrill.com]
  • Template paths with dot chars in them no longer mess up implicit template selection for multipart messages 3332 [Chad Fowler]
  • Make sure anything with content-disposition of "attachment" is passed to the attachment presenter when parsing an email body [Jamis Buck]
  • Make sure TMail#attachments includes anything with content-disposition of "attachment", regardless of content-type [Jamis Buck]

*1.1.5* (December 13th, 2005)

  • Become part of Rails 1.0

*1.1.4* (December 7th, 2005)

  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]
  • Stricter matching for implicitly multipart filenames excludes files ending in unsupported extensions (such as foo.rhtml.bak) and without a two-part content type (such as foo.text.rhtml or foo.text.really.plain.rhtml). 2398 [Dave Burt <dave@burt.id.au>, Jeremy Kemper]

*1.1.3* (November 7th, 2005)

  • Allow Mailers to have custom initialize methods that set default instance variables for all mail actions 2563 [mrj@bigpond.net.au]

*1.1.2* (October 26th, 2005)

  • Upgraded to Action Pack 1.10.2

*1.1.1* (October 19th, 2005)

  • Upgraded to Action Pack 1.10.1

*1.1.0* (October 16th, 2005)

  • Update and extend documentation (rdoc)
  • Minero Aoki made TMail available to Rails/ActionMailer under the MIT license (instead of LGPL) [RubyConf ‘05]
  • Austin Ziegler made Text::Simple available to Rails/ActionMailer under a MIT-like licens [See rails ML, subject "Text::Format Licence Exception" on Oct 15, 2005]
  • Fix vendor require paths to prevent files being required twice
  • Don‘t add charset to content-type header for a part that contains subparts (for AOL compatibility) 2013 [John Long]
  • Preserve underscores when unquoting message bodies 1930
  • Encode multibyte characters correctly 1894
  • Multipart messages specify a MIME-Version header automatically 2003 [John Long]
  • Add a unified render method to ActionMailer (delegates to ActionView::Base#render)
  • Move mailer initialization to a separate (overridable) method, so that subclasses may alter the various defaults 1727
  • Look at content-location header (if available) to determine filename of attachments 1670
  • ActionMailer::Base.deliver(email) had been accidentally removed, but was documented in the Rails book 1849
  • Fix problem with sendmail delivery where headers should be delimited by \n characters instead of \r\n, which confuses some mail readers 1742 [Kent Sibilev]

*1.0.1* (11 July, 2005)

  • Bind to Action Pack 1.9.1

*1.0.0* (6 July, 2005)

  • Avoid adding nil header values 1392
  • Better multipart support with implicit multipart/alternative and sorting of subparts [John Long]
  • Allow for nested parts in multipart mails 1570 [Flurin Egger]
  • Normalize line endings in outgoing mail bodies to "\n" 1536 [John Long]
  • Allow template to be explicitly specified 1448 [tuxie@dekadance.se]
  • Allow specific "multipart/xxx" content-type to be set on multipart messages 1412 [Flurin Egger]
  • Unquoted @ characters in headers are now accepted in spite of RFC 822 1206
  • Helper support (borrowed from ActionPack)
  • Silently ignore Errno::EINVAL errors when converting text.
  • Don‘t cause an error when parsing an encoded attachment name 1340 [lon@speedymac.com]
  • Nested multipart message parts are correctly processed in TMail::Mail#body
  • BCC headers are removed when sending via SMTP 1402
  • Added ‘content_type’ accessor, to allow content type to be set on a per-message basis. content_type defaults to "text/plain".
  • Silently ignore Iconv::IllegalSequence errors when converting text 1341 [lon@speedymac.com]
  • Support attachments and multipart messages.
  • Added new accessors for the various mail properties.
  • Fix to only perform the charset conversion if a ‘from’ and a ‘to’ charset are given (make no assumptions about what the charset was) 1276 [Jamis Buck]
  • Fix attachments and content-type problems 1276 [Jamis Buck]
  • Fixed the TMail#body method to look at the content-transfer-encoding header and unquote the body according to the rules it specifies 1265 [Jamis Buck]
  • Added unquoting even if the iconv lib can‘t be loaded—in that case, only the charset conversion is skipped 1265 [Jamis Buck]
  • Added automatic decoding of base64 bodies 1214 [Jamis Buck]
  • Added that delivery errors are caught in a way so the mail is still returned whether the delivery was successful or not
  • Fixed that email address like "Jamis Buck, M.D." <wild.medicine@example.net> would cause the quoter to generate emails resulting in "bad address" errors from the mail server 1220 [Jamis Buck]

*0.9.1* (20th April, 2005)

  • Depend on Action Pack 1.8.1

*0.9.0* (19th April, 2005)

  • Added that deliver_* will now return the email that was sent
  • Added that quoting to UTF-8 only happens if the characters used are in that range 955 [Jamis Buck]
  • Fixed quoting for all address headers, not just to 955 [Jamis Buck]
  • Fixed unquoting of emails that doesn‘t have an explicit charset 1036 [wolfgang@stufenlos.net]

*0.8.1* (27th March, 2005)

  • Fixed that if charset was found that the end of a mime part declaration TMail would throw an error 919 [lon@speedymac.com]
  • Fixed that TMail::Unquoter would fail to recognize quoting method if it was in lowercase 919 [lon@speedymac.com]
  • Fixed that TMail::Encoder would fail when it attempts to parse e-mail addresses which are encoded using something other than the messages encoding method 919 [lon@speedymac.com]
  • Added rescue for missing iconv library and throws warnings if subject/body is called on a TMail object without it instead

*0.8.0* (22th March, 2005)

  • Added framework support for processing incoming emails with an Action Mailer class. See example in README.

*0.7.1* (7th March, 2005)

  • Bind to newest Action Pack (1.5.1)

*0.7.0* (24th February, 2005)

  • Added support for charsets for both subject and body. The default charset is now UTF-8 673 [Jamis Buck]. Examples:
      def iso_charset(recipient)
    @recipients = recipient
    @subject    = "testing iso charsets"
    @from       = "system@loudthinking.com"
    @body       = "Nothing to see here."
    @charset    = "iso-8859-1"
  end

  def unencoded_subject(recipient)
    @recipients = recipient
    @subject    = "testing unencoded subject"
    @from       = "system@loudthinking.com"
    @body       = "Nothing to see here."
    @encode_subject = false
    @charset    = "iso-8859-1"
  end

*0.6.1* (January 18th, 2005)

  • Fixed sending of emails to use Tmail#from not the deprecated Tmail#from_address

*0.6* (January 17th, 2005)

  • Fixed that bcc and cc should be settable through @bcc and @cc — not just @headers["Bcc"] and @headers["Cc"] 453 [Eric Hodel]
  • Fixed Action Mailer to be "warnings safe" so you can run with ruby -w and not get framework warnings 453 [Eric Hodel]

*0.5*

  • Added access to custom headers, like cc, bcc, and reply-to 268 [Andreas Schwarz]. Example:
      def post_notification(recipients, post)
    @recipients          = recipients
    @from                = post.author.email_address_with_name
    @headers["bcc"]      = SYSTEM_ADMINISTRATOR_EMAIL
    @headers["reply-to"] = "notifications@example.com"
    @subject             = "[#{post.account.name} #{post.title}]"
    @body["post"]        = post
  end

*0.4* (5)

  • Consolidated the server configuration options into Base#server_settings= and expanded that with controls for authentication and more [Marten] NOTE: This is an API change that could potentially break your application if you used the old application form. Please do change!
  • Added Base#deliveries as an accessor for an array of emails sent out through that ActionMailer class when using the :test delivery option. [Jeremy Kemper]
  • Added Base#perform_deliveries= which can be set to false to turn off the actual delivery of the email through smtp or sendmail. This is especially useful for functional testing that shouldn‘t send off real emails, but still trigger delivery_* methods.
  • Added option to specify delivery method with Base#delivery_method=. Default is :smtp and :sendmail is currently the only other option. Sendmail is assumed to be present at "/usr/sbin/sendmail" if that option is used. [Kent Sibilev]
  • Dropped "include TMail" as it added to much baggage into the default namespace (like Version) [Chad Fowler]

*0.3*

  • First release


File: README

File
README
Path: | actionpack/README
Modified: | Sun Mar 02 11:08:57 -0700 2008

Action Pack — On rails from request to response

Action Pack splits the response to a web request into a controller part (performing the logic) and a view part (rendering a template). This two-step approach is known as an action, which will normally create, read, update, or delete (CRUD for short) some sort of model part (often backed by a database) before choosing either to render a template or redirecting to another action.

Action Pack implements these actions as public methods on Action Controllers and uses Action Views to implement the template rendering. Action Controllers are then responsible for handling all the actions relating to a certain part of an application. This grouping usually consists of actions for lists and for CRUDs revolving around a single (or a few) model objects. So ContactController would be responsible for listing contacts, creating, deleting, and updating contacts. A WeblogController could be responsible for both posts and comments.

Action View templates are written using embedded Ruby in tags mingled in with the HTML. To avoid cluttering the templates with code, a bunch of helper classes provide common behavior for forms, dates, and strings. And it‘s easy to add specific helpers to keep the separation as the application evolves.

Note: Some of the features, such as scaffolding and form building, are tied to ActiveRecord (an object-relational mapping package), but that doesn‘t mean that Action Pack depends on Active Record. Action Pack is an independent package that can be used with any sort of backend (Instiki, which is based on an older version of Action Pack, used Madeleine for example). Read more about the role Action Pack can play when used together with Active Record on www.rubyonrails.org.

A short rundown of the major features:

  • Actions grouped in controller as methods instead of separate command objects and can therefore share helper methods.
      BlogController < ActionController::Base
    def show
      @customer = find_customer
    end

    def update
      @customer = find_customer
      @customer.attributes = params[:customer]
      @customer.save ?
        redirect_to(:action => "display") :
        render(:action => "edit")
    end

    private
      def find_customer() Customer.find(params[:id]) end
  end

    Learn more

  • Embedded Ruby for templates (no new "easy" template language)
      <% for post in @posts %>
    Title: <%= post.title %>
  <% end %>

  All post titles: <%= @post.collect{ |p| p.title }.join ", " %>

  <% unless @person.is_client? %>
    Not for clients to see...
  <% end %>

    Learn more

  • Builder-based templates (great for XML content, like RSS)
      xml.rss("version" => "2.0") do
    xml.channel do
      xml.title(@feed_title)
      xml.link(@url)
      xml.description "Basecamp: Recent items"
      xml.language "en-us"
      xml.ttl "40"

      for item in @recent_items
        xml.item do
          xml.title(item_title(item))
          xml.description(item_description(item))
          xml.pubDate(item_pubDate(item))
          xml.guid(@recent_items.url(item))
          xml.link(@recent_items.url(item))
        end
      end
    end
  end

    Learn more

  • Filters for pre and post processing of the response (as methods, procs, and classes)
      class WeblogController < ActionController::Base
    before_filter :authenticate, :cache, :audit
    after_filter { |c| c.response.body = GZip::compress(c.response.body) }
    after_filter LocalizeFilter

    def index
      # Before this action is run, the user will be authenticated, the cache
      # will be examined to see if a valid copy of the results already
      # exists, and the action will be logged for auditing.

      # After this action has run, the output will first be localized then
      # compressed to minimize bandwidth usage
    end

    private
      def authenticate
        # Implement the filter with full access to both request and response
      end
  end

    Learn more

  • Helpers for forms, dates, action links, and text
      <%= text_field "post", "title", "size" => 30 %>
  <%= html_date_select(Date.today) %>
  <%= link_to "New post", :controller => "post", :action => "new" %>
  <%= truncate(post.title, 25) %>

    Learn more

  • Layout sharing for template reuse (think simple version of Struts Tiles)
      class WeblogController < ActionController::Base
    layout "weblog_layout"

    def hello_world
    end
  end

  Layout file (called weblog_layout):
    <html><body><%= yield %></body></html>

  Template for hello_world action:
    <h1>Hello world</h1>

  Result of running hello_world action:
    <html><body><h1>Hello world</h1></body></html>

    Learn more

  • Routing makes pretty urls incredibly easy
      map.connect 'clients/:client_name/:project_name/:controller/:action'

  Accessing /clients/37signals/basecamp/project/dash calls ProjectController#dash with
  { "client_name" => "37signals", "project_name" => "basecamp" } in params[:params]

  From that URL, you can rewrite the redirect in a number of ways:

  redirect_to(:action => "edit") =>
    /clients/37signals/basecamp/project/dash

  redirect_to(:client_name => "nextangle", :project_name => "rails") =>
    /clients/nextangle/rails/project/dash

    Learn more

  • Javascript and Ajax integration.
      link_to_function "Greeting", "alert('Hello world!')"
  link_to_remote "Delete this post", :update => "posts",
                 :url => { :action => "destroy", :id => post.id }

    Learn more

  • Pagination for navigating lists of results.
      # controller
  def list
    @pages, @people =
      paginate :people, :order => 'last_name, first_name'
  end

  # view
  <%= link_to "Previous page", { :page => @pages.current.previous } if @pages.current.previous %>
  <%= link_to "Next page", { :page => @pages.current.next } if @pages.current.next %>

    Learn more

  • Easy testing of both controller and template result through TestRequest/Response
      class LoginControllerTest < Test::Unit::TestCase
    def setup
      @controller = LoginController.new
      @request    = ActionController::TestRequest.new
      @response   = ActionController::TestResponse.new
    end

    def test_failing_authenticate
      process :authenticate, :user_name => "nop", :password => ""
      assert flash.has_key?(:alert)
      assert_redirected_to :action => "index"
    end
  end

    Learn more

  • Automated benchmarking and integrated logging
      Processing WeblogController#index (for 127.0.0.1 at Fri May 28 00:41:55)
  Parameters: {"action"=>"index", "controller"=>"weblog"}
  Rendering weblog/index (200 OK)
  Completed in 0.029281 (34 reqs/sec)

  If Active Record is used as the model, you'll have the database debugging
  as well:

  Processing WeblogController#create (for 127.0.0.1 at Sat Jun 19 14:04:23)
  Params: {"controller"=>"weblog", "action"=>"create",
           "post"=>{"title"=>"this is good"} }
  SQL (0.000627) INSERT INTO posts (title) VALUES('this is good')
  Redirected to http://test/weblog/display/5
  Completed in 0.221764 (4 reqs/sec) | DB: 0.059920 (27%)

  You specify a logger through a class method, such as:

  ActionController::Base.logger = Logger.new("Application Log")
  ActionController::Base.logger = Log4r::Logger.new("Application Log")
  • Caching at three levels of granularity (page, action, fragment)
      class WeblogController < ActionController::Base
    caches_page :show
    caches_action :account

    def show
      # the output of the method will be cached as
      # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
      # and the web server will pick it up without even hitting Rails
    end

    def account
      # the output of the method will be cached in the fragment store
      # but Rails is hit to retrieve it, so filters are run
    end

    def update
      List.update(params[:list][:id], params[:list])
      expire_page   :action => "show", :id => params[:list][:id]
      expire_action :action => "account"
      redirect_to   :action => "show", :id => params[:list][:id]
    end
  end

    Learn more

  • Component requests from one controller to another
      class WeblogController < ActionController::Base
    # Performs a method and then lets hello_world output its render
    def delegate_action
      do_other_stuff_before_hello_world
      render_component :controller => "greeter",  :action => "hello_world"
    end
  end

  class GreeterController < ActionController::Base
    def hello_world
      render_text "Hello World!"
    end
  end

  The same can be done in a view to do a partial rendering:

    Let's see a greeting:
    <%= render_component :controller => "greeter", :action => "hello_world" %>

    Learn more

  • Powerful debugging mechanism for local requests
      All exceptions raised on actions performed on the request of a local user
  will be presented with a tailored debugging screen that includes exception
  message, stack trace, request parameters, session contents, and the
  half-finished response.

    Learn more

  • Scaffolding for Active Record model objects
      class AccountController < ActionController::Base
    scaffold :account
  end

  The AccountController now has the full CRUD range of actions and default
  templates: list, show, destroy, new, create, edit, update

    Learn more

  • Form building for Active Record model objects
      The post object has a title (varchar), content (text), and
  written_on (date)

  <%= form "post" %>

  ...will generate something like (the selects will have more options, of
  course):

  <form action="create" method="POST">
    <p>
      <b>Title:</b><br/>
      <input type="text" name="post[title]" value="<%= @post.title %>" />
    </p>
    <p>
      <b>Content:</b><br/>
      <textarea name="post[content]"><%= @post.title %></textarea>
    </p>
    <p>
      <b>Written on:</b><br/>
      <select name='post[written_on(3i)]'><option>18</option></select>
      <select name='post[written_on(2i)]'><option value='7'>July</option></select>
      <select name='post[written_on(1i)]'><option>2004</option></select>
    </p>

    <input type="submit" value="Create">
  </form>

  This form generates a params[:post] array that can be used directly in a save action:

  class WeblogController < ActionController::Base
    def create
      post = Post.create(params[:post])
      redirect_to :action => "display", :id => post.id
    end
  end

    Learn more

  • Runs on top of WEBrick, Mongrel, CGI, FCGI, and mod_ruby

Simple example (from outside of Rails)

This example will implement a simple weblog system using inline templates and an Active Record model. So let‘s build that WeblogController with just a few methods:

  require 'action_controller'
  require 'post'

  class WeblogController < ActionController::Base
    layout "weblog/layout"

    def index
      @posts = Post.find(:all)
    end

    def display
      @post = Post.find(params[:id])
    end

    def new
      @post = Post.new
    end

    def create
      @post = Post.create(params[:post])
      redirect_to :action => "display", :id => @post.id
    end
  end

  WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
  WeblogController.process_cgi if $0 == __FILE__

The last two lines are responsible for telling ActionController where the template files are located and actually running the controller on a new request from the web-server (like to be Apache).

And the templates look like this:

  weblog/layout.erb:
    <html><body>
    <%= yield %>
    </body></html>

  weblog/index.erb:
    <% for post in @posts %>
      <p><%= link_to(post.title, :action => "display", :id => post.id %></p>
    <% end %>

  weblog/display.erb:
    <p>
      <b><%= post.title %></b><br/>
      <b><%= post.content %></b>
    </p>

  weblog/new.erb:
    <%= form "post" %>

This simple setup will list all the posts in the system on the index page, which is called by accessing /weblog/. It uses the form builder for the Active Record model to make the new screen, which in turn hands everything over to the create action (that‘s the default target for the form builder when given a new model). After creating the post, it‘ll redirect to the display page using an URL such as /weblog/display/5 (where 5 is the id of the post).

Examples

Action Pack ships with three examples that all demonstrate an increasingly detailed view of the possibilities. First is blog_controller that is just a single file for the whole MVC (but still split into separate parts). Second is the debate_controller that uses separate template files and multiple screens. Third is the address_book_controller that uses the layout feature to separate template casing from content.

Please note that you might need to change the "shebang" line to #!/usr/local/env ruby, if your Ruby is not placed in /usr/local/bin/ruby

Also note that these examples are all for demonstrating using Action Pack on its own. Not for when it‘s used inside of Rails.

Download

The latest version of Action Pack can be found at

  • rubyforge.org/project/showfiles.php?group_id=249

Documentation can be found at

  • api.rubyonrails.com

Installation

You can install Action Pack with the following command.

  % [sudo] ruby install.rb

from its distribution directory.

License

Action Pack is released under the MIT license.

Support

The Action Pack homepage is www.rubyonrails.org. You can find the Action Pack RubyForge page at rubyforge.org/projects/actionpack. And as Jim from Rake says:

   Feel free to submit commits or feature requests.  If you send a patch,
   remember to update the corresponding unit tests.  If fact, I prefer
   new feature to be submitted in the form of new unit tests.


Class: ActionController::Base

Class
ActionController::Base
In: | actionpack/lib/action_controller/base.rb actionpack/lib/action_controller/cgi_process.rb actionpack/lib/action_controller/test_process.rb
Parent: | Object

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)
    end

    def sign
      Entry.create(params[:entry])
      redirect_to :action => "index"
    end
  end

Actions, by default, render a template in the app/views 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 app/views/guestbook/index.erb by default after populating the @entries instance variable.

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.

Requests

Requests are processed by the Action Controller framework by extracting the value of the "action" key in the request parameters. This value should hold the name of the action to be performed. Once the action has been identified, the remaining request parameters, the session (if one is available), and the full request with all the http headers are made available to the action through instance variables. Then the action is performed.

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 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 method which returns a hash. For example, an action that was performed through /weblog/list?category=All&limit=5 will include { "category" => "All", "limit" => 5 } in params.

It‘s also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:

  <input type="text" name="post[name]" value="david">
  <input type="text" name="post[address]" value="hyacintvej">

A request stemming from a form holding these inputs will include {
"post" => { "name" => "david",
"address" => "hyacintvej" } }. If the address
input had been named "post[address][street]", the params would
have included { "post" => { "address" => {
"street" => "hyacintvej" } } }. There‘s
no limit to the depth of the nesting.

Sessions

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 session method, which accesses a hash:

  session[:person] = Person.authenticate(user_name, password)

And retrieved again through the same hash:

  Hello #{session[:person]}

For removing objects from the session, you can either assign a single key to nil, like session[:person] = nil, or you can remove the entire session with reset_session.

Sessions are stored in a browser cookie that‘s cryptographically signed, but unencrypted, by default. This prevents the user from tampering with the session but also allows him to see its contents.

Do not put secret information in session!

Other options for session storage are:

ActiveRecordStore: sessions are stored in your database, which works better than PStore with multiple app servers and, unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set

  config.action_controller.session_store = :active_record_store

in your environment.rb and run rake db:sessions:create.

MemCacheStore: sessions are stored as entries in your memcached cache. Set the session store type in environment.rb:

  config.action_controller.session_store = :mem_cache_store

 This assumes that memcached has been installed and configured properly.  See the MemCacheStore docs for more information.

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 and requires no user intervention.

Renders

Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It‘s automatically configured. The controller passes objects to the view by assigning instance variables:

  def show
    @post = Post.find(params[:id])
  end

Which are then automatically available to the view:

  Title: <%= @post.title %>

You don‘t have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use the manual rendering methods:

  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"
    end
  end

Read more about writing ERb and Builder templates in classes/ActionView/Base.html.

Redirects

Redirects are used to move from one action to another. For example, after a create 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 show action that we‘ll assume has already been created. The code might look like this:

  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

In this case, after saving our new entry to the database, the user is redirected to the show method which is then executed.

Calling multiple redirects or renders

An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:

  def do_something
    redirect_to :action => "elsewhere"
    render :action => "overthere" # raises DoubleRenderError
  end

If you need to redirect on the condition of something, then be sure to add "and return" to halt execution.

  def do_something
    redirect_to(:action => "elsewhere") and return if monkeys.nil?
    render :action => "overthere" # won't be called unless monkeys is nil
  end
Methods
  • append_view_path
  • append_view_path
  • controller_class_name
  • controller_class_name
  • controller_name
  • controller_name
  • controller_path
  • controller_path
  • default_url_options
  • exempt_from_layout
  • expires_in
  • expires_now
  • filter_parameter_logging
  • head
  • hidden_actions
  • hide_action
  • prepend_view_path
  • prepend_view_path
  • process_cgi
  • process_test
  • process_with_test
  • redirect_to
  • render
  • render_to_string
  • reset_session
  • session_enabled?
  • url_for
  • view_paths
  • view_paths
  • view_paths=
  • view_paths=
Included Modules
  • StatusCodes
Constants
DEFAULT_RENDER_STATUS_CODE = "200 OK"
Attributes
[RW] | action_name | Returns the name of the action this controller is processing.
[RW] | assigns | Holds the hash of variables that are passed on to the template class to be made available to the view. This hash is generated by taking a snapshot of all the instance variables in the current scope just before a template is rendered.
Public Class methods
append_view_path(path)

Adds a view_path to the end of the view_paths array. If the current class has no view paths, copy them from the superclass. This change will be visible for all future requests.

  ArticleController.append_view_path("views/default")
  ArticleController.append_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 452
452:       def append_view_path(path)
453:         @view_paths = superclass.view_paths.dup if @view_paths.nil?
454:         view_paths.push(*path)
455:       end
controller_class_name()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 392
392:       def controller_class_name
393:         @controller_class_name ||= name.demodulize
394:       end
controller_name()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 397
397:       def controller_name
398:         @controller_name ||= controller_class_name.sub(/Controller$/, '').underscore
399:       end
controller_path()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 402
402:       def controller_path
403:         @controller_path ||= name.gsub(/Controller$/, '').underscore
404:       end
exempt_from_layout(*extensions)

Don‘t render layouts for templates with the given extensions.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 506
506:       def exempt_from_layout(*extensions)
507:         regexps = extensions.collect do |extension|
508:           extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
509:         end
510:         @@exempt_from_layout.merge regexps
511:       end
filter_parameter_logging(*filter_words) {|key, value| ...}

Replace sensitive parameter data from the request log. Filters parameters 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 parameter 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]"

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 480
480:       def filter_parameter_logging(*filter_words, &block)
481:         parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
482:
483:         define_method(:filter_parameters) do |unfiltered_parameters|
484:           filtered_parameters = {}
485:
486:           unfiltered_parameters.each do |key, value|
487:             if key =~ parameter_filter
488:               filtered_parameters[key] = '[FILTERED]'
489:             elsif value.is_a?(Hash)
490:               filtered_parameters[key] = filter_parameters(value)
491:             elsif block_given?
492:               key = key.dup
493:               value = value.dup if value
494:               yield key, value
495:               filtered_parameters[key] = value
496:             else
497:               filtered_parameters[key] = value
498:             end
499:           end
500:
501:           filtered_parameters
502:         end
503:       end
hidden_actions()

Return an array containing the names of public methods that have been marked hidden from the action processor. By default, all methods defined in ActionController::Base and included modules are hidden. More methods can be hidden using hide_actions.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 409
409:       def hidden_actions
410:         unless read_inheritable_attribute(:hidden_actions)
411:           write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map(&:to_s))
412:         end
413:
414:         read_inheritable_attribute(:hidden_actions)
415:       end
hide_action(*names)

Hide each of the given methods from being callable as actions.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 418
418:       def hide_action(*names)
419:         write_inheritable_attribute(:hidden_actions, hidden_actions | names.map(&:to_s))
420:       end
prepend_view_path(path)

Adds a view_path to the front of the view_paths array. If the current class has no view paths, copy them from the superclass. This change will be visible for all future requests.

  ArticleController.prepend_view_path("views/default")
  ArticleController.prepend_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 440
440:       def prepend_view_path(path)
441:         @view_paths = superclass.view_paths.dup if @view_paths.nil?
442:         view_paths.unshift(*path)
443:       end
process_cgi(cgi = CGI.new, session_options = {})

Process a request extracted from an CGI object and return a response. Pass false as session_options to disable sessions (large performance increase if sessions are not needed). The session_options are the same as for CGI::Session:

  • :database_manager - standard options are CGI::Session::FileStore,
CGI::Session::MemoryStore, and CGI::Session::PStore (default).
Additionally, there is CGI::Session::DRbStore and
CGI::Session::ActiveRecordStore. Read more about these in
lib/action_controller/session.
  • :session_key - the parameter name used for the session id. Defaults to ‘_session_id’.
  • :session_id - the session id to use. If not provided, then it is retrieved from the session_key cookie, or automatically generated for a new session.
  • :new_session - if true, force creation of a new session. If not set, a new session is only created if none currently exists. If false, a new session is never created, and if none currently exists and the session_id option is not set, an ArgumentError is raised.
  • :session_expires - the time the current session expires, as a Time object. If not set, the session will continue indefinitely.
  • :session_domain - the hostname domain for which this session is valid. If not set, defaults to the hostname of the server.
  • :session_secure - if true, this session will only work over HTTPS.
  • :session_path - the path for which this session applies. Defaults to the directory of the CGI script.
  • :cookie_only - if true (the default), session IDs will only be accepted from cookies and not from the query string or POST parameters. This protects against session fixation attacks.

[ show source ]

    # File actionpack/lib/action_controller/cgi_process.rb, line 26
26:     def self.process_cgi(cgi = CGI.new, session_options = {})
27:       new.process_cgi(cgi, session_options)
28:     end
process_test(request)

Process a test request called with a TestRequest object.

[ show source ]

   # File actionpack/lib/action_controller/test_process.rb, line 6
6:     def self.process_test(request)
7:       new.process_test(request)
8:     end
view_paths()

View load paths determine the bases from which template references can be made. So a call to render("test/template") will be looked up in the view load paths array and the closest match will be returned.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 425
425:       def view_paths
426:         @view_paths || superclass.view_paths
427:       end
view_paths=(value)

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 429
429:       def view_paths=(value)
430:         @view_paths = value
431:       end
Public Instance methods
append_view_path(path)

Adds a view_path to the end of the view_paths array. This change affects the current request only.

  self.append_view_path("views/default")
  self.append_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 668
668:       def append_view_path(path)
669:         (@template || self.class).append_view_path(path)
670:       end
controller_class_name()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 623
623:       def controller_class_name
624:         self.class.controller_class_name
625:       end
controller_name()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 628
628:       def controller_name
629:         self.class.controller_name
630:       end
controller_path()

Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 633
633:       def controller_path
634:         self.class.controller_path
635:       end
prepend_view_path(path)

Adds a view_path to the front of the view_paths array. This change affects the current request only.

  self.prepend_view_path("views/default")
  self.prepend_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 658
658:       def prepend_view_path(path)
659:         (@template || self.class).prepend_view_path(path)
660:       end
process_with_test(*args)

[ show source ]

    # File actionpack/lib/action_controller/test_process.rb, line 14
14:     def process_with_test(*args)
15:       returning process_without_test(*args) do
16:         add_variables_to_assigns
17:       end
18:     end
session_enabled?()

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 637
637:       def session_enabled?
638:         request.session_options && request.session_options[:disabled] != false
639:       end
url_for(options = nil)

Returns a URL that has been rewritten according to the options hash and the defined Routes. (For doing a complete redirect, use redirect_to). url_for is used to: All keys given to url_for are forwarded to the Route module, save for the following:

  • :anchor — specifies the anchor name to be appended to the path. For example, url_for :controller => ‘posts’, :action => ‘show’, :id => 10, :anchor => ‘comments‘ will produce "/posts/show/10#comments".
  • :only_path — if true, returns the relative URL (omitting the protocol, host name, and port) (false by default)
  • :trailing_slash — if true, adds a trailing slash, as in "/archive/2005/". Note that this is currently not recommended since it breaks caching.
  • :host — overrides the default (current) host if provided.
  • :protocol — overrides the default (current) protocol if provided.
  • :port — optionally specify the port to connect to.
  • :user — Inline HTTP authentication (only plucked out if :password is also present).
  • :password — Inline HTTP authentication (only plucked out if :user is also present).
  • :skip_relative_url_root — if true, the url is not constructed using the relative_url_root of the request so the path will include the web server relative installation directory.

The URL is generated from the remaining keys in the hash. A URL contains two key parts: the <base> and a query string. Routes composes a query string as the key/value pairs not included in the <base>.

The default Routes setup supports a typical Rails path of "controller/action/id" where action and id are optional, with action defaulting to ‘index’ when not given. Here are some typical url_for statements and their corresponding URLs:

  url_for :controller => 'posts', :action => 'recent'                # => 'proto://host.com/posts/recent'
  url_for :controller => 'posts', :action => 'index'                 # => 'proto://host.com/posts'
  url_for :controller => 'posts', :action => 'index', :port=>'8033'  # => 'proto://host.com:8033/posts'
  url_for :controller => 'posts', :action => 'show', :id => 10       # => 'proto://host.com/posts/show/10'
  url_for :controller => 'posts', :user => 'd', :password => '123'   # => 'proto://d:123@host.com/posts'

When generating a new URL, missing values may be filled in from the current request‘s parameters. For example, url_for :action => ‘some_action‘ will retain the current controller, as expected. This behavior extends to other parameters, including :controller, :id, and any other parameters that are placed into a Route‘s path. The URL helpers such as url_for have a limited form of memory: when generating a new URL, they can look for missing values in the current request‘s parameters. Routes attempts to guess when a value should and should not be taken from the defaults. There are a few simple rules on how this is performed:

  • If the controller name begins with a slash, no defaults are used: url_for :controller => ’/home‘
  • If the controller changes, the action will default to index unless provided

The final rule is applied while the URL is being generated and is best illustrated by an example. Let us consider the route given by map.connect ‘people/:last/:first/:action’, :action => ‘bio’, :controller => ‘people‘.

Suppose that the current URL is "people/hh/david/contacts". Let‘s consider a few different cases of URLs which are generated from this page.

  • url_for :action => ‘bio‘ — During the generation of this URL, default values will be used for the first and

last components, and the action shall change. The generated URL will be, "people/hh/david/bio".

  • url_for :first => ‘davids-little-brother‘ This generates the URL ‘people/hh/davids-little-brother’ — note that this URL leaves out the assumed action of ‘bio’.

However, you might ask why the action from the current request, ‘contacts’, isn‘t carried over into the new URL. The answer has to do with the order in which the parameters appear in the generated path. In a nutshell, since the value that appears in the slot for :first is not equal to default value for :first we stop using defaults. On its own, this rule can account for much of the typical Rails URL behavior. Although a convenience, defaults can occasionally get in your way. In some cases a default persists longer than desired. The default may be cleared by adding :name => nil to url_for‘s options. This is often required when writing form helpers, since the defaults in play may vary greatly depending upon where the helper is used from. The following line will redirect to PostController‘s default action, regardless of the page it is displayed on:

  url_for :controller => 'posts', :action => nil

If you explicitly want to create a URL that‘s almost the same as the current URL, you can do so using the :overwrite_params options. Say for your posts you have different views for showing and printing them. Then, in the show view, you get the URL for the print view like this

  url_for :overwrite_params => { :action => 'print' }

This takes the current URL as is and only exchanges the action. In contrast, url_for :action => ‘print‘ would have slashed-off the path components after the changed action.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 611
611:       def url_for(options = nil) #:doc:
612:         case options || {}
613:           when String
614:             options
615:           when Hash
616:             @url.rewrite(rewrite_options(options))
617:           else
618:             polymorphic_url(options)
619:         end
620:       end
view_paths()

View load paths for controller.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 644
644:       def view_paths
645:         (@template || self.class).view_paths
646:       end
view_paths=(value)

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 648
648:       def view_paths=(value)
649:         (@template || self.class).view_paths = value
650:       end
Protected Instance methods
default_url_options(options)

Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in the form of a hash, just like the one you would use for url_for directly. Example:

  def default_url_options(options)
    { :project => @project.active? ? @project.url_name : "unknown" }
  end

As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set by this method.

[ show source ]

      # File actionpack/lib/action_controller/base.rb, line 1000
1000:       def default_url_options(options) #:doc:
1001:       end
expires_in(seconds, options = {})

Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that intermediate caches shouldn‘t cache the response.

Examples:

  expires_in 20.minutes
  expires_in 3.hours, :private => false
  expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true

This method will overwrite an existing Cache-Control header. See www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.

[ show source ]

      # File actionpack/lib/action_controller/base.rb, line 1074
1074:       def expires_in(seconds, options = {}) #:doc:
1075:         cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys)
1076:         cache_options.delete_if { |k,v| v.nil? or v == false }
1077:         cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
1078:         response.headers["Cache-Control"] = cache_control.join(', ')
1079:       end
expires_now(

Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or intermediate caches (like caching proxy servers).

[ show source ]

      # File actionpack/lib/action_controller/base.rb, line 1083
1083:       def expires_now #:doc:
1084:         response.headers["Cache-Control"] = "no-cache"
1085:       end
head(*args)

Return a response that has no content (merely headers). The options argument is interpreted to be a hash of header names and values. This allows you to easily return a response that consists only of significant headers:

  head :created, :location => person_path(@person)

It can also be used to return exceptional conditions:

  return head(:method_not_allowed) unless request.post?
  return head(:bad_request) unless valid_request?
  render

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 941
941:       def head(*args)
942:         if args.length > 2
943:           raise ArgumentError, "too many arguments to head"
944:         elsif args.empty?
945:           raise ArgumentError, "too few arguments to head"
946:         end
947:         options = args.extract_options!
948:         status = interpret_status(args.shift || options.delete(:status) || :ok)
949:
950:         options.each do |key, value|
951:           headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
952:         end
953:
954:         render :nothing => true, :status => status
955:       end
redirect_to(options = {}, response_status = {})

Redirects the browser to the target specified in options. This parameter can take one of three forms:

  • Hash - The URL will be generated by calling url_for with the options.
  • Record - The URL will be generated by calling url_for with the options, which will reference a named URL for that record.
  • String starting with protocol:// (like http://) - Is passed straight through as the target for redirection.
  • String not containing a protocol - The current protocol and host is prepended to the string.
  • :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. Short-hand for redirect_to(request.env["HTTP_REFERER"])

Examples:

  redirect_to :action => "show", :id => 5
  redirect_to post
  redirect_to "http://www.rubyonrails.org"
  redirect_to "/images/screenshot.jpg"
  redirect_to articles_url
  redirect_to :back

The redirection happens as a "302 Moved" header unless otherwise specified.

Examples:

  redirect_to post_url(@post), :status=>:found
  redirect_to :action=>'atom', :status=>:moved_permanently
  redirect_to post_url(@post), :status=>301
  redirect_to :action=>'atom', :status=>302

When using redirect_to :back, if there is no referrer, RedirectBackError will be raised. You may specify some fallback behavior for this case by rescuing RedirectBackError.

[ show source ]

      # File actionpack/lib/action_controller/base.rb, line 1031
1031:       def redirect_to(options = {}, response_status = {}) #:doc:
1032:
1033:         if options.is_a?(Hash) && options[:status]
1034:           status = options.delete(:status)
1035:         elsif response_status[:status]
1036:           status = response_status[:status]
1037:         else
1038:           status = 302
1039:         end
1040:
1041:         case options
1042:           when %r{^\w+://.*}
1043:             raise DoubleRenderError if performed?
1044:             logger.info("Redirected to #{options}") if logger && logger.info?
1045:             response.redirect(options, interpret_status(status))
1046:             response.redirected_to = options
1047:             @performed_redirect = true
1048:
1049:           when String
1050:             redirect_to(request.protocol + request.host_with_port + options, :status=>status)
1051:
1052:           when :back
1053:             request.env["HTTP_REFERER"] ? redirect_to(request.env["HTTP_REFERER"], :status=>status) : raise(RedirectBackError)
1054:
1055:           when Hash
1056:             redirect_to(url_for(options), :status=>status)
1057:             response.redirected_to = options
1058:
1059:           else
1060:             redirect_to(url_for(options), :status=>status)
1061:         end
1062:       end
render(options = nil, &block)

Renders the content that will be returned to the browser as the response body.

Rendering an action

Action rendering is the most common form and the type used automatically by Action Controller when nothing else is specified. By default, actions are rendered within the current layout (if one exists).

  # Renders the template for the action "goal" within the current controller
  render :action => "goal"

  # Renders the template for the action "short_goal" within the current controller,
  # but without the current active layout
  render :action => "short_goal", :layout => false

  # Renders the template for the action "long_goal" within the current controller,
  # but with a custom layout
  render :action => "long_goal", :layout => "spectacular"

Rendering partials

Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page without reloading. Rendering of partials from the controller makes it possible to use the same partial template in both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the controller action responding to Ajax calls). By default, the current layout is not used.

  # Renders the same partial with a local variable.
  render :partial => "person", :locals => { :name => "david" }

  # Renders the partial, making @new_person available through
  # the local variable 'person'
  render :partial => "person", :object => @new_person

  # Renders a collection of the same partial by making each element
  # of @winners available through the local variable "person" as it
  # builds the complete response.
  render :partial => "person", :collection => @winners

  # Renders the same collection of partials, but also renders the
  # person_divider partial between each person partial.
  render :partial => "person", :collection => @winners, :spacer_template => "person_divider"

  # Renders a collection of partials located in a view subfolder
  # outside of our current controller.  In this example we will be
  # rendering app/views/shared/_note.r(html|xml)  Inside the partial
  # each element of @new_notes is available as the local var "note".
  render :partial => "shared/note", :collection => @new_notes

  # Renders the partial with a status code of 500 (internal error).
  render :partial => "broken", :status => 500

Note that the partial filename must also be a valid Ruby variable name, so e.g. 2005 and register-user are invalid.

Automatic etagging

Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified and the response body will be set to an empty string. No etag header will be inserted if it‘s already set.

Rendering a template

Template rendering works just like action rendering except that it takes a path relative to the template root. The current layout is automatically applied.

  # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
  render :template => "weblog/show"

Rendering a file

File rendering works just like action rendering except that it takes a filesystem path. By default, the path is assumed to be absolute, and the current layout is not applied.

  # Renders the template located at the absolute filesystem path
  render :file => "/path/to/some/template.erb"
  render :file => "c:/path/to/some/template.erb"

  # Renders a template within the current layout, and with a 404 status code
  render :file => "/path/to/some/template.erb", :layout => true, :status => 404
  render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404

  # Renders a template relative to the template root and chooses the proper file extension
  render :file => "some/template", :use_full_path => true

Rendering text

Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text rendering is not done within the active layout.

  # Renders the clear text "hello world" with status code 200
  render :text => "hello world!"

  # Renders the clear text "Explosion!"  with status code 500
  render :text => "Explosion!", :status => 500

  # Renders the clear text "Hi there!" within the current active layout (if one exists)
  render :text => "Hi there!", :layout => true

  # Renders the clear text "Hi there!" within the layout
  # placed in "app/views/layouts/special.r(html|xml)"
  render :text => "Hi there!", :layout => "special"

The :text option can also accept a Proc object, which can be used to manually control the page generation. This should generally be avoided, as it violates the separation between code and content, and because almost everything that can be done with this method can also be done more cleanly using one of the other rendering methods, most notably templates.

  # Renders "Hello from code!"
  render :text => proc { |response, output| output.write("Hello from code!") }

Rendering JSON

Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected that the response will be parsed (or eval‘d) for use as a data structure.

  # Renders '{"name": "David"}'
  render :json => {:name => "David"}.to_json

It‘s not necessary to call to_json on the object you want to render, since render will automatically do that for you:

  # Also renders '{"name": "David"}'
  render :json => {:name => "David"}

Sometimes the result isn‘t handled directly by a script (such as when the request comes from a SCRIPT tag), so the :callback option is provided for these cases.

  # Renders 'show({"name": "David"})'
  render :json => {:name => "David"}.to_json, :callback => 'show'

Rendering an inline template

Rendering of an inline template works as a cross between text and action rendering where the source for the template is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering and the current layout is not used.

  # Renders "hello, hello, hello, again"
  render :inline => "<%= 'hello, ' * 3 + 'again' %>"

  # Renders "<p>Good seeing you!</p>" using Builder
  render :inline => "xml.p { 'Good seeing you!' }", :type => :builder

  # Renders "hello david"
  render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }

Rendering inline JavaScriptGenerator page updates

In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details), you can also pass the :update parameter to render, along with a block, to render page updates inline.

  render :update do |page|
    page.replace_html  'user_list', :partial => 'user', :collection => @users
    page.visual_effect :highlight, 'user_list'
  end

Rendering with status and location headers

All renders take the :status and :location options and turn them into headers. They can even be used together:

  render :xml => post.to_xml, :status => :created, :location => post_url(post)

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 832
832:       def render(options = nil, &block) #:doc:
833:         raise DoubleRenderError, "Can only render or redirect once per action" if performed?
834:
835:         if options.nil?
836:           return render_for_file(default_template_name, nil, true)
837:         else
838:           if options == :update
839:             options = { :update => true }
840:           elsif !options.is_a?(Hash)
841:             raise RenderError, "You called render with invalid options : #{options}"
842:           end
843:         end
844:
845:         if content_type = options[:content_type]
846:           response.content_type = content_type.to_s
847:         end
848:
849:         if location = options[:location]
850:           response.headers["Location"] = url_for(location)
851:         end
852:
853:         if text = options[:text]
854:           render_for_text(text, options[:status])
855:
856:         else
857:           if file = options[:file]
858:             render_for_file(file, options[:status], options[:use_full_path], options[:locals] || {})
859:
860:           elsif template = options[:template]
861:             render_for_file(template, options[:status], true)
862:
863:           elsif inline = options[:inline]
864:             add_variables_to_assigns
865:             render_for_text(@template.render_template(options[:type], inline, nil, options[:locals] || {}), options[:status])
866:
867:           elsif action_name = options[:action]
868:             template = default_template_name(action_name.to_s)
869:             if options[:layout] && !template_exempt_from_layout?(template)
870:               render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)
871:             else
872:               render_with_no_layout(:file => template, :status => options[:status], :use_full_path => true)
873:             end
874:
875:           elsif xml = options[:xml]
876:             response.content_type ||= Mime::XML
877:             render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
878:
879:           elsif json = options[:json]
880:             json = json.to_json unless json.is_a?(String)
881:             json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
882:             response.content_type ||= Mime::JSON
883:             render_for_text(json, options[:status])
884:
885:           elsif partial = options[:partial]
886:             partial = default_template_name if partial == true
887:             add_variables_to_assigns
888:
889:             if collection = options[:collection]
890:               render_for_text(
891:                 @template.send!(:render_partial_collection, partial, collection,
892:                 options[:spacer_template], options[:locals]), options[:status]
893:               )
894:             else
895:               render_for_text(
896:                 @template.send!(:render_partial, partial,
897:                 ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status]
898:               )
899:             end
900:
901:           elsif options[:update]
902:             add_variables_to_assigns
903:             @template.send! :evaluate_assigns
904:
905:             generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
906:             response.content_type = Mime::JS
907:             render_for_text(generator.to_s)
908:
909:           elsif options[:nothing]
910:             # Safari doesn't pass the headers of the return if the response is zero length
911:             render_for_text(" ", options[:status])
912:
913:           else
914:             render_for_file(default_template_name, options[:status], true)
915:           end
916:         end
917:       end
render_to_string(options = nil, &block)

Renders according to the same rules as render, but returns the result in a string instead of sending it as the response body to the browser.

[ show source ]

     # File actionpack/lib/action_controller/base.rb, line 921
921:       def render_to_string(options = nil, &block) #:doc:
922:         render(options, &block)
923:       ensure
924:         erase_render_results
925:         forget_variables_added_to_assigns
926:         reset_variables_added_to_assigns
927:       end
reset_session(

Resets the session by clearing out all the objects stored within and initializing a new session object.

[ show source ]

      # File actionpack/lib/action_controller/base.rb, line 1088
1088:       def reset_session #:doc:
1089:         request.reset_session
1090:         @_session = request.session
1091:         response.session = @_session
1092:       end


Class: ActionController::AbstractRequest

Class
ActionController::AbstractRequest
In: | actionpack/lib/action_controller/request.rb
Parent: | Object

CgiRequest and TestRequest provide concrete implementations.

Methods
  • accepts
  • body
  • content_length
  • content_type
  • content_type_with_parameters
  • content_type_without_parameters
  • delete?
  • domain
  • format
  • format=
  • get?
  • head?
  • headers
  • host
  • host_with_port
  • method
  • parameters
  • path
  • path_parameters
  • port
  • port_string
  • post?
  • protocol
  • put?
  • query_string
  • raw_post
  • relative_url_root
  • remote_ip
  • request_method
  • request_uri
  • server_software
  • ssl?
  • standard_port
  • subdomains
  • symbolized_path_parameters
  • url
  • xhr?
  • xml_http_request?
Constants
MULTIPART_BOUNDARY | = | %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
EOL | = | "\015\012"
Attributes
[R] env The hash of environment variables for this request, such as { ‘RAILS_ENV’ => ‘production’ }.
Public Instance methods
accepts()

Returns the accepted MIME type for the request

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 81
81:     def accepts
82:       @accepts ||=
83:         if @env['HTTP_ACCEPT'].to_s.strip.empty?
84:           [ content_type, Mime::ALL ].compact # make sure content_type being nil is not included
85:         else
86:           Mime::Type.parse(@env['HTTP_ACCEPT'])
87:         end
88:     end
body()

The request body is an IO input stream.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 316
316:     def body
317:     end
content_length()

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 68
68:     def content_length
69:       @content_length ||= env['CONTENT_LENGTH'].to_i
70:     end
content_type()

The MIME type of the HTTP request, such as Mime::XML.

For backward compatibility, the post format is extracted from the X-Post-Data-Format HTTP header if present.

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 76
76:     def content_type
77:       @content_type ||= Mime::Type.lookup(content_type_without_parameters)
78:     end
delete?()

Is this a DELETE request? Equivalent to request.method == :delete

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 54
54:     def delete?
55:       request_method == :delete
56:     end
domain(tld_length = 1)

Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify a different tld_length, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 202
202:     def domain(tld_length = 1)
203:       return nil unless named_host?(host)
204:
205:       host.split('.').last(1 + tld_length).join('.')
206:     end
format()

Returns the Mime type for the format used in the request. If there is no format available, the first of the accept types will be used. Examples:

  GET /posts/5.xml   | request.format => Mime::XML
  GET /posts/5.xhtml | request.format => Mime::HTML
  GET /posts/5       | request.format => request.accepts.first (usually Mime::HTML for browsers)

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 96
96:     def format
97:       @format ||= parameters[:format] ? Mime::Type.lookup_by_extension(parameters[:format]) : accepts.first
98:     end
format=(extension)

Sets the format by string extension, which can be used to force custom formats that are not controlled by the extension. Example:

  class ApplicationController < ActionController::Base
    before_filter :adjust_format_for_iphone

    private
      def adjust_format_for_iphone
        request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
      end
  end

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 112
112:     def format=(extension)
113:       parameters[:format] = extension.to_s
114:       format
115:     end
get?()

Is this a GET (or HEAD) request? Equivalent to request.method == :get

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 39
39:     def get?
40:       method == :get
41:     end
head?()

Is this a HEAD request? request.method sees HEAD as :get, so check the HTTP method directly.

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 60
60:     def head?
61:       request_method == :head
62:     end
headers()

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 64
64:     def headers
65:       @env
66:     end
host()

Returns the host for this request, such as example.com.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 172
172:     def host
173:     end
host_with_port()

Returns a host:port string for this request, such as example.com or example.com:8080.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 177
177:     def host_with_port
178:       @host_with_port ||= host + port_string
179:     end
method()

The HTTP request method as a lowercase symbol, such as :get. Note, HEAD is returned as :get since the two are functionally equivalent from the application‘s perspective.

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 34
34:     def method
35:       request_method == :head ? :get : request_method
36:     end
parameters()

Returns both GET and POST parameters in a single hash.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 286
286:     def parameters
287:       @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
288:     end
path()

Returns the interpreted path to requested resource after all the installation directory of this application was taken into account

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 251
251:     def path
252:       path = (uri = request_uri) ? uri.split('?').first.to_s : ''
253:
254:       # Cut off the path to the installation directory if given
255:       path.sub!(%r/^#{relative_url_root}/, '')
256:       path || ''
257:     end
path_parameters()

Returns a hash with the parameters used to form the path of the request. Returned hash keys are strings. See symbolized_path_parameters for symbolized keys.

Example:

  {'action' => 'my_action', 'controller' => 'my_controller'}

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 306
306:     def path_parameters
307:       @path_parameters ||= {}
308:     end
port()

Returns the port number of this request as an integer.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 182
182:     def port
183:       @port_as_int ||= @env['SERVER_PORT'].to_i
184:     end
port_string()

Returns a port suffix like ":8080" if the port number of this request is not the default HTTP port 80 or HTTPS port 443.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 196
196:     def port_string
197:       (port == standard_port) ? '' : ":#{port}"
198:     end
post?()

Is this a POST request? Equivalent to request.method == :post

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 44
44:     def post?
45:       request_method == :post
46:     end
protocol()

Return ‘https://’ if this is an SSL request and ‘http://’ otherwise.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 162
162:     def protocol
163:       ssl? ? 'https://' : 'http://'
164:     end
put?()

Is this a PUT request? Equivalent to request.method == :put

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 49
49:     def put?
50:       request_method == :put
51:     end
query_string()

Return the query string, accounting for server idiosyncracies.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 218
218:     def query_string
219:       if uri = @env['REQUEST_URI']
220:         uri.split('?', 2)[1] || ''
221:       else
222:         @env['QUERY_STRING'] || ''
223:       end
224:     end
raw_post()

Read the request body. This is useful for web services that need to work with raw requests directly.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 277
277:     def raw_post
278:       unless env.include? 'RAW_POST_DATA'
279:         env['RAW_POST_DATA'] = body.read(content_length)
280:         body.rewind if body.respond_to?(:rewind)
281:       end
282:       env['RAW_POST_DATA']
283:     end
relative_url_root()

Returns the path minus the web server relative installation directory. This can be set with the environment variable RAILS_RELATIVE_URL_ROOT. It can be automatically extracted for Apache setups. If the server is not Apache, this method returns an empty string.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 263
263:     def relative_url_root
264:       @@relative_url_root ||= case
265:         when @env["RAILS_RELATIVE_URL_ROOT"]
266:           @env["RAILS_RELATIVE_URL_ROOT"]
267:         when server_software == 'apache'
268:           @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
269:         else
270:           ''
271:       end
272:     end
remote_ip()

Determine originating IP address. REMOTE_ADDR is the standard but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR are set by proxies so check for these before falling back to REMOTE_ADDR. HTTP_X_FORWARDED_FOR may be a comma- delimited list in the case of multiple chained proxies; the first is the originating IP.

Security note: do not use if IP spoofing is a concern for your application. Since remote_ip checks HTTP headers for addresses forwarded by proxies, the client may send any IP. remote_addr can‘t be spoofed but also doesn‘t work behind a proxy, since it‘s always the proxy‘s IP.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 136
136:     def remote_ip
137:       return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP'
138:
139:       if @env.include? 'HTTP_X_FORWARDED_FOR' then
140:         remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
141:           ip.strip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
142:         end
143:
144:         return remote_ips.first.strip unless remote_ips.empty?
145:       end
146:
147:       @env['REMOTE_ADDR']
148:     end
request_method()

The true HTTP request method as a lowercase symbol, such as :get. UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.

[ show source ]

    # File actionpack/lib/action_controller/request.rb, line 20
20:     def request_method
21:       @request_method ||= begin
22:         method = ((@env['REQUEST_METHOD'] == 'POST' && !parameters[:_method].blank?) ? parameters[:_method].to_s : @env['REQUEST_METHOD']).downcase
23:         if ACCEPTED_HTTP_METHODS.include?(method)
24:           method.to_sym
25:         else
26:           raise UnknownHttpMethod, "#{method}, accepted HTTP methods are #{ACCEPTED_HTTP_METHODS.to_a.to_sentence}"
27:         end
28:       end
29:     end
request_uri()

Return the request URI, accounting for server idiosyncracies. WEBrick includes the full URL. IIS leaves REQUEST_URI blank.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 228
228:     def request_uri
229:       if uri = @env['REQUEST_URI']
230:         # Remove domain, which webrick puts into the request_uri.
231:         (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
232:       else
233:         # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
234:         script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
235:         uri = @env['PATH_INFO']
236:         uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
237:         unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
238:           uri << '?' << env_qs
239:         end
240:
241:         if uri.nil?
242:           @env.delete('REQUEST_URI')
243:           uri
244:         else
245:           @env['REQUEST_URI'] = uri
246:         end
247:       end
248:     end
server_software()

Returns the lowercase name of the HTTP server software.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 151
151:     def server_software
152:       (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
153:     end
ssl?()

Is this an SSL request?

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 167
167:     def ssl?
168:       @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
169:     end
standard_port()

Returns the standard port number for this request‘s protocol

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 187
187:     def standard_port
188:       case protocol
189:         when 'https://' then 443
190:         else 80
191:       end
192:     end
subdomains(tld_length = 1)

Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org". You can specify a different tld_length, such as 2 to catch ["www"] instead of ["www", "rubyonrails"] in "www.rubyonrails.co.uk".

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 211
211:     def subdomains(tld_length = 1)
212:       return [] unless named_host?(host)
213:       parts = host.split('.')
214:       parts[0..-(tld_length+2)]
215:     end
symbolized_path_parameters()

The same as path_parameters with explicitly symbolized keys

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 296
296:     def symbolized_path_parameters
297:       @symbolized_path_parameters ||= path_parameters.symbolize_keys
298:     end
url()

Returns the complete URL used for this request

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 157
157:     def url
158:       protocol + host_with_port + request_uri
159:     end
xhr?()

Alias for xml_http_request?

xml_http_request?()

Returns true if the request‘s "X-Requested-With" header contains "XMLHttpRequest". (The Prototype Javascript library sends this header with every Ajax request.)

This method is also aliased as xhr?

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 120
120:     def xml_http_request?
121:       !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
122:     end
Protected Instance methods
content_type_with_parameters()

The raw content type string. Use when you need parameters such as charset or boundary which aren‘t included in the content_type MIME type. Overridden by the X-POST_DATA_FORMAT header for backward compatibility.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 342
342:       def content_type_with_parameters
343:         content_type_from_legacy_post_data_format_header ||
344:           env['CONTENT_TYPE'].to_s
345:       end
content_type_without_parameters()

The raw content type string with its parameters stripped off.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 348
348:       def content_type_without_parameters
349:         @content_type_without_parameters ||= self.class.extract_content_type_without_parameters(content_type_with_parameters)
350:       end


Module: ActionController::Assertions

Module
ActionController::Assertions
In: actionpack/lib/action_controller/assertions/dom_assertions.rb actionpack/lib/action_controller/assertions/model_assertions.rb actionpack/lib/action_controller/assertions/response_assertions.rb actionpack/lib/action_controller/assertions/routing_assertions.rb actionpack/lib/action_controller/assertions/selector_assertions.rb actionpack/lib/action_controller/assertions/tag_assertions.rb actionpack/lib/action_controller/assertions.rb

In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions can be used against. These collections are:

  • assigns: Instance variables assigned in the action that are available for the view.
  • session: Objects being saved in the session.
  • flash: The flash objects currently in the session.
  • cookies: Cookies being sent to the user on this request.

These collections can be used just like any other hash:

  assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
  assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
  assert flash.empty? # makes sure that there's nothing in the flash

For historic reasons, the assigns hash uses string-based keys. So assigns[:person] won‘t work, but assigns["person"] will. To appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing. So assigns(:person) will work just like assigns["person"], but again, assigns[:person] will not work.

On top of the collections, you have the complete url that a given action redirected to available in redirect_to_url.

For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another action call which can then be asserted against.

Manipulating the request collections

The collections described above link to the response, so you can test if what the actions were expected to do happened. But sometimes you also want to manipulate these collections in the incoming request. This is really only relevant for sessions and cookies, though. For sessions, you just do:

  @request.session[:key] = "value"

For cookies, you need to manually create the cookie, like this:

  @request.cookies["key"] = CGI::Cookie.new("key", "value")

Testing named routes

If you‘re using named routes, they can be easily tested using the original named routes’ methods straight in the test case. Example:

 assert_redirected_to page_url(:title => 'foo')
Methods
  • clean_backtrace
  • included
Classes and Modules
Module ActionController::Assertions::DomAssertions
Module ActionController::Assertions::ModelAssertions
Module ActionController::Assertions::ResponseAssertions
Module ActionController::Assertions::RoutingAssertions
Module ActionController::Assertions::SelectorAssertions
Module ActionController::Assertions::TagAssertions
Constants
NO_STRIP = %w{pre script style textarea}
Public Class methods
included(klass)

[ show source ]

    # File actionpack/lib/action_controller/assertions.rb, line 46
46:     def self.included(klass)
47:       %w(response selector tag dom routing model).each do |kind|
48:         require "action_controller/assertions/#{kind}_assertions"
49:         klass.module_eval { include const_get("#{kind.camelize}Assertions") }
50:       end
51:     end
Public Instance methods
clean_backtrace() {|| ...}

[ show source ]

    # File actionpack/lib/action_controller/assertions.rb, line 53
53:     def clean_backtrace(&block)
54:       yield
55:     rescue Test::Unit::AssertionFailedError => error
56:       framework_path = Regexp.new(File.expand_path("#{File.dirname(__FILE__)}/assertions"))
57:       error.backtrace.reject! { |line| File.expand_path(line) =~ framework_path }
58:       raise
59:     end


Module: ActionController::Assertions::DomAssertions

Module
ActionController::Assertions::DomAssertions
In: actionpack/lib/action_controller/assertions/dom_assertions.rb
Methods
  • assert_dom_equal
  • assert_dom_not_equal
Public Instance methods
assert_dom_equal(expected, actual, message = "")

Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)

Examples

  # assert that the referenced method generates the appropriate HTML string
  assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com")

[ show source ]

    # File actionpack/lib/action_controller/assertions/dom_assertions.rb, line 11
11:       def assert_dom_equal(expected, actual, message = "")
12:         clean_backtrace do
13:           expected_dom = HTML::Document.new(expected).root
14:           actual_dom   = HTML::Document.new(actual).root
15:           full_message = build_message(message, "<?> expected to be == to\n<?>.", expected_dom.to_s, actual_dom.to_s)
16:
17:           assert_block(full_message) { expected_dom == actual_dom }
18:         end
19:       end
assert_dom_not_equal(expected, actual, message = "")

The negated form of assert_dom_equivalent.

Examples

  # assert that the referenced method does not generate the specified HTML string
  assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com")

[ show source ]

    # File actionpack/lib/action_controller/assertions/dom_assertions.rb, line 28
28:       def assert_dom_not_equal(expected, actual, message = "")
29:         clean_backtrace do
30:           expected_dom = HTML::Document.new(expected).root
31:           actual_dom   = HTML::Document.new(actual).root
32:           full_message = build_message(message, "<?> expected to be != to\n<?>.", expected_dom.to_s, actual_dom.to_s)
33:
34:           assert_block(full_message) { expected_dom != actual_dom }
35:         end
36:       end


Module: ActionController::Assertions::ModelAssertions

Module
ActionController::Assertions::ModelAssertions
In: actionpack/lib/action_controller/assertions/model_assertions.rb
Methods
  • assert_valid
Public Instance methods
assert_valid(record)

Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not.

Examples

  # assert that a newly created record is valid
  model = Model.new
  assert_valid(model)

[ show source ]

    # File actionpack/lib/action_controller/assertions/model_assertions.rb, line 12
12:       def assert_valid(record)
13:         clean_backtrace do
14:           assert record.valid?, record.errors.full_messages.join("\n")
15:         end
16:       end


Module: ActionController::Assertions::ResponseAssertions

Module
ActionController::Assertions::ResponseAssertions
In: actionpack/lib/action_controller/assertions/response_assertions.rb

A small suite of assertions that test responses from Rails applications.

Methods
  • assert_redirected_to
  • assert_response
  • assert_template
Public Instance methods
assert_redirected_to(options = {}, message=nil)

Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that assert_redirected_to(:controller => "weblog") will also match the redirection of redirect_to(:controller => "weblog", :action => "show") and so on.

Examples

  # assert that the redirection was to the "index" action on the WeblogController
  assert_redirected_to :controller => "weblog", :action => "index"

  # assert that the redirection was to the named route login_url
  assert_redirected_to login_url

[ show source ]

     # File actionpack/lib/action_controller/assertions/response_assertions.rb, line 53
 53:       def assert_redirected_to(options = {}, message=nil)
 54:         clean_backtrace do
 55:           assert_response(:redirect, message)
 56:           return true if options == @response.redirected_to
 57:           ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
 58:
 59:           begin
 60:             url  = {}
 61:             original = { :expected => options, :actual => @response.redirected_to.is_a?(Symbol) ? @response.redirected_to : @response.redirected_to.dup }
 62:             original.each do |key, value|
 63:               if value.is_a?(Symbol)
 64:                 value = @controller.respond_to?(value, true) ? @controller.send(value) : @controller.send("hash_for_#{value}_url")
 65:               end
 66:
 67:               unless value.is_a?(Hash)
 68:                 request = case value
 69:                   when NilClass    then nil
 70:                   when /^\w+:\/\// then recognized_request_for(%r{^(\w+://.*?(/|$|\?))(.*)$} =~ value ? $3 : nil)
 71:                   else                  recognized_request_for(value)
 72:                 end
 73:                 value = request.path_parameters if request
 74:               end
 75:
 76:               if value.is_a?(Hash) # stringify 2 levels of hash keys
 77:                 if name = value.delete(:use_route)
 78:                   route = ActionController::Routing::Routes.named_routes[name]
 79:                   value.update(route.parameter_shell)
 80:                 end
 81:
 82:                 value.stringify_keys!
 83:                 value.values.select { |v| v.is_a?(Hash) }.collect { |v| v.stringify_keys! }
 84:                 if key == :expected && value['controller'] == @controller.controller_name && original[:actual].is_a?(Hash)
 85:                   original[:actual].stringify_keys!
 86:                   value.delete('controller') if original[:actual]['controller'].nil? || original[:actual]['controller'] == value['controller']
 87:                 end
 88:               end
 89:
 90:               if value.respond_to?(:[]) && value['controller']
 91:                 value['controller'] = value['controller'].to_s
 92:                 if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
 93:                   new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
 94:                   value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path)
 95:                 end
 96:                 value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
 97:               end
 98:               url[key] = value
 99:             end
100:
101:             @response_diff = url[:actual].diff(url[:expected]) if url[:actual]
102:             msg = build_message(message, "expected a redirect to <?>, found one to <?>, a difference of <?> ", url[:expected], url[:actual], @response_diff)
103:
104:             assert_block(msg) do
105:               url[:expected].keys.all? do |k|
106:                 if k == :controller then url[:expected][k] == ActionController::Routing.controller_relative_to(url[:actual][k], @controller.class.controller_path)
107:                 else parameterize(url[:expected][k]) == parameterize(url[:actual][k])
108:                 end
109:               end
110:             end
111:           rescue ActionController::RoutingError # routing failed us, so match the strings only.
112:             msg = build_message(message, "expected a redirect to <?>, found one to <?>", options, @response.redirect_url)
113:             url_regexp = %r{^(\w+://.*?(/|$|\?))(.*)$}
114:             eurl, epath, url, path = [options, @response.redirect_url].collect do |url|
115:               u, p = (url_regexp =~ url) ? [$1, $3] : [nil, url]
116:               [u, (p.first == '/') ? p : '/' + p]
117:             end.flatten
118:
119:             assert_equal(eurl, url, msg) if eurl && url
120:             assert_equal(epath, path, msg) if epath && path
121:           end
122:         end
123:       end
assert_response(type, message = nil)

Asserts that the response is one of the following types:

  • :success - Status code was 200
  • :redirect - Status code was in the 300-399 range
  • :missing - Status code was 404
  • :error - Status code was in the 500-599 range

You can also pass an explicit status number like assert_response(501) or its symbolic equivalent assert_response(:not_implemented). See ActionController::StatusCodes for a full list.

Examples

  # assert that the response was a redirection
  assert_response :redirect

  # assert that the response code was status code 401 (unauthorized)
  assert_response 401

[ show source ]

    # File actionpack/lib/action_controller/assertions/response_assertions.rb, line 27
27:       def assert_response(type, message = nil)
28:         clean_backtrace do
29:           if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?")
30:             assert_block("") { true } # to count the assertion
31:           elsif type.is_a?(Fixnum) && @response.response_code == type
32:             assert_block("") { true } # to count the assertion
33:           elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
34:             assert_block("") { true } # to count the assertion
35:           else
36:             assert_block(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) { false }
37:           end
38:         end
39:       end
assert_template(expected = nil, message=nil)

Asserts that the request was rendered with the appropriate template file.

Examples

  # assert that the "new" view template was rendered
  assert_template "new"

[ show source ]

     # File actionpack/lib/action_controller/assertions/response_assertions.rb, line 132
132:       def assert_template(expected = nil, message=nil)
133:         clean_backtrace do
134:           rendered = expected ? @response.rendered_file(!expected.include?('/')) : @response.rendered_file
135:           msg = build_message(message, "expecting <?> but rendering with <?>", expected, rendered)
136:           assert_block(msg) do
137:             if expected.nil?
138:               !@response.rendered_with_file?
139:             else
140:               expected == rendered
141:             end
142:           end
143:         end
144:       end


Module: ActionController::Assertions::RoutingAssertions

Module
ActionController::Assertions::RoutingAssertions
In: actionpack/lib/action_controller/assertions/routing_assertions.rb

Suite of assertions to test routes generated by Rails and the handling of requests made to them.

Methods
  • assert_generates
  • assert_recognizes
  • assert_routing
Public Instance methods
assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)

Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.

The defaults parameter is unused.

Examples

  # Asserts that the default action is generated for a route with no action
  assert_generates("/items", :controller => "items", :action => "index")

  # Tests that the list action is properly routed
  assert_generates("/items/list", :controller => "items", :action => "list")

  # Tests the generation of a route with a parameter
  assert_generates("/items/list/1", { :controller => "items", :action => "list", :id => "1" })

  # Asserts that the generated route gives us our custom route
  assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }

[ show source ]

    # File actionpack/lib/action_controller/assertions/routing_assertions.rb, line 80
80:       def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
81:         clean_backtrace do
82:           expected_path = "/#{expected_path}" unless expected_path[0] == ?/
83:           # Load routes.rb if it hasn't been loaded.
84:           ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
85:
86:           generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults)
87:           found_extras = options.reject {|k, v| ! extra_keys.include? k}
88:
89:           msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
90:           assert_block(msg) { found_extras == extras }
91:
92:           msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
93:               expected_path)
94:           assert_block(msg) { expected_path == generated_path }
95:         end
96:       end
assert_recognizes(expected_options, path, extras={}, message=nil)

Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.

Pass a hash in the second argument (path) to specify the request method. This is useful for routes requiring a specific HTTP method. The hash should contain a :path with the incoming request path and a :method containing the required HTTP verb.

  # assert that POSTing to /items will call the create action on ItemsController
  assert_recognizes({:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post})

You can also pass in extras with a hash containing URL parameters that would normally be in the query string. This can be used to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the extras argument, appending the query string on the path directly will not work. For example:

  # assert that a path of '/items/list/1?view=print' returns the correct options
  assert_recognizes({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })

The message parameter allows you to pass in an error message that is displayed upon failure.

Examples

  # Check the default route (i.e., the index action)
  assert_recognizes({:controller => 'items', :action => 'index'}, 'items')

  # Test a specific action
  assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list')

  # Test an action with a parameter
  assert_recognizes({:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1')

  # Test a custom route
  assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1')

  # Check a Simply RESTful generated route
  assert_recognizes(list_items_url, 'items/list')

[ show source ]

    # File actionpack/lib/action_controller/assertions/routing_assertions.rb, line 39
39:       def assert_recognizes(expected_options, path, extras={}, message=nil)
40:         if path.is_a? Hash
41:           request_method = path[:method]
42:           path           = path[:path]
43:         else
44:           request_method = nil
45:         end
46:
47:         clean_backtrace do
48:           ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
49:           request = recognized_request_for(path, request_method)
50:
51:           expected_options = expected_options.clone
52:           extras.each_key { |key| expected_options.delete key } unless extras.nil?
53:
54:           expected_options.stringify_keys!
55:           routing_diff = expected_options.diff(request.path_parameters)
56:           msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
57:               request.path_parameters, expected_options, expected_options.diff(request.path_parameters))
58:           assert_block(msg) { request.path_parameters == expected_options }
59:         end
60:       end
assert_routing(path, options, defaults={}, extras={}, message=nil)

Asserts that path and options match both ways; in other words, it verifies that path generates options and then that options generates path. This essentially combines assert_recognizes and assert_generates into one step.

The extras hash allows you to specify options that would normally be provided as a query string to the action. The message parameter allows you to specify a custom error message to display upon failure.

Examples

 # Assert a basic route: a controller with the default action (index)
 assert_routing('/home', :controller => 'home', :action => 'index')

 # Test a route generated with a specific controller, action, and parameter (id)
 assert_routing('/entries/show/23', :controller => 'entries', :action => 'show', id => 23)

 # Assert a basic route (controller + default action), with an error message if it fails
 assert_routing('/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly')

 # Tests a route, providing a defaults hash
 assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"}

[ show source ]

     # File actionpack/lib/action_controller/assertions/routing_assertions.rb, line 117
117:       def assert_routing(path, options, defaults={}, extras={}, message=nil)
118:         assert_recognizes(options, path, extras, message)
119:
120:         controller, default_controller = options[:controller], defaults[:controller]
121:         if controller && controller.include?(?/) && default_controller && default_controller.include?(?/)
122:           options[:controller] = "/#{controller}"
123:         end
124:
125:         assert_generates(path, options, defaults, extras, message)
126:       end


Module: ActionController::Assertions::SelectorAssertions

Module
ActionController::Assertions::SelectorAssertions
In: actionpack/lib/action_controller/assertions/selector_assertions.rb

Adds the assert_select method for use in Rails functional test cases, which can be used to make assertions on the response HTML of a controller action. You can also call assert_select within another assert_select to make assertions on elements selected by the enclosing assertion.

Use css_select to select elements without making an assertions, either from the response HTML or elements selected by the enclosing assertion.

In addition to HTML responses, you can make the following assertions:

  • assert_select_rjs — Assertions on HTML content of RJS update and
      insertion operations.
  • assert_select_encoded — Assertions on HTML encoded inside XML,
      for example for dealing with feed item descriptions.
  • assert_select_email — Assertions on the HTML body of an e-mail.

Also see HTML::Selector to learn how to use selectors.

Methods
  • assert_select
  • assert_select_email
  • assert_select_encoded
  • assert_select_rjs
  • css_select
  • response_from_page_or_rjs
  • unescape_rjs
Constants
RJS_STATEMENTS | = | { :replace => /Element\.replace/, :replace_html => /Element\.update/, :chained_replace => /\.replace/, :chained_replace_html => /\.update/, :remove => /Element\.remove/, :show => /Element\.show/, :hide => /Element\.hide/, :toggle => /Element\.toggle/
RJS_INSERTIONS | = | [:top, :bottom, :before, :after]
RJS_PATTERN_HTML | = | /"((\\"|[^"])*)"/
RJS_PATTERN_EVERYTHING | = | Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
RJS_PATTERN_UNICODE_ESCAPED_CHAR | = | /\\u([0-9a-zA-Z]{4})/
Public Instance methods
assert_select(selector, equality?, message?)
assert_select(element, selector, equality?, message?)

An assertion that selects elements and makes one or more equality tests.

If the first argument is an element, selects all matching elements starting from (and including) that element and all its children in depth-first order.

If no element if specified, calling assert_select will select from the response HTML. Calling assert_select inside an assert_select block will run the assertion for each element selected by the enclosing assertion.

Example

  assert_select "ol>li" do |elements|
    elements.each do |element|
      assert_select element, "li"
    end
  end

Or for short:

  assert_select "ol>li" do
    assert_select "li"
  end

The selector may be a CSS selector expression (String), an expression with substitution values, or an HTML::Selector object.

Equality Tests

The equality test may be one of the following:

  • true — Assertion is true if at least one element selected.
  • false — Assertion is true if no element selected.
  • String/Regexp — Assertion is true if the text value of at least one element matches the string or regular expression.
  • Integer — Assertion is true if exactly that number of elements are selected.
  • Range — Assertion is true if the number of selected elements fit the range.

If no equality test specified, the assertion is true if at least one element selected.

To perform more than one equality tests, use a hash with the following keys:

  • :text — Narrow the selection to elements that have this text value (string or regexp).
  • :html — Narrow the selection to elements that have this HTML content (string or regexp).
  • :count — Assertion is true if the number of selected elements is equal to this value.
  • :minimum — Assertion is true if the number of selected elements is at least this value.
  • :maximum — Assertion is true if the number of selected elements is at most this value.

If the method is called with a block, once all equality tests are evaluated the block is called with an array of all matched elements.

Examples

  # At least one form element
  assert_select "form"

  # Form element includes four input fields
  assert_select "form input", 4

  # Page title is "Welcome"
  assert_select "title", "Welcome"

  # Page title is "Welcome" and there is only one title element
  assert_select "title", {:count=>1, :text=>"Welcome"},
      "Wrong title or more than one title element"

  # Page contains no forms
  assert_select "form", false, "This page must contain no forms"

  # Test the content and style
  assert_select "body div.header ul.menu"

  # Use substitution values
  assert_select "ol>li#?", /item-\d+/

  # All input fields in the form have a name
  assert_select "form input" do
    assert_select "[name=?]", /.+/  # Not empty
  end

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 193
193:       def assert_select(*args, &block)
194:         # Start with optional element followed by mandatory selector.
195:         arg = args.shift
196:
197:         if arg.is_a?(HTML::Node)
198:           # First argument is a node (tag or text, but also HTML root),
199:           # so we know what we're selecting from.
200:           root = arg
201:           arg = args.shift
202:         elsif arg == nil
203:           # This usually happens when passing a node/element that
204:           # happens to be nil.
205:           raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?"
206:         elsif @selected
207:           root = HTML::Node.new(nil)
208:           root.children.concat @selected
209:         else
210:           # Otherwise just operate on the response document.
211:           root = response_from_page_or_rjs
212:         end
213:
214:         # First or second argument is the selector: string and we pass
215:         # all remaining arguments. Array and we pass the argument. Also
216:         # accepts selector itself.
217:         case arg
218:           when String
219:             selector = HTML::Selector.new(arg, args)
220:           when Array
221:             selector = HTML::Selector.new(*arg)
222:           when HTML::Selector
223:             selector = arg
224:           else raise ArgumentError, "Expecting a selector as the first argument"
225:         end
226:
227:         # Next argument is used for equality tests.
228:         equals = {}
229:         case arg = args.shift
230:           when Hash
231:             equals = arg
232:           when String, Regexp
233:             equals[:text] = arg
234:           when Integer
235:             equals[:count] = arg
236:           when Range
237:             equals[:minimum] = arg.begin
238:             equals[:maximum] = arg.end
239:           when FalseClass
240:             equals[:count] = 0
241:           when NilClass, TrueClass
242:             equals[:minimum] = 1
243:           else raise ArgumentError, "I don't understand what you're trying to match"
244:         end
245:
246:         # By default we're looking for at least one match.
247:         if equals[:count]
248:           equals[:minimum] = equals[:maximum] = equals[:count]
249:         else
250:           equals[:minimum] = 1 unless equals[:minimum]
251:         end
252:
253:         # Last argument is the message we use if the assertion fails.
254:         message = args.shift
255:         #- message = "No match made with selector #{selector.inspect}" unless message
256:         if args.shift
257:           raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type"
258:         end
259:
260:         matches = selector.select(root)
261:         # If text/html, narrow down to those elements that match it.
262:         content_mismatch = nil
263:         if match_with = equals[:text]
264:           matches.delete_if do |match|
265:             text = ""
266:             stack = match.children.reverse
267:             while node = stack.pop
268:               if node.tag?
269:                 stack.concat node.children.reverse
270:               else
271:                 text << node.content
272:               end
273:             end
274:             text.strip! unless NO_STRIP.include?(match.name)
275:             unless match_with.is_a?(Regexp) ? (text =~ match_with) : (text == match_with.to_s)
276:               content_mismatch ||= build_message(message, "<?> expected but was\n<?>.", match_with, text)
277:               true
278:             end
279:           end
280:         elsif match_with = equals[:html]
281:           matches.delete_if do |match|
282:             html = match.children.map(&:to_s).join
283:             html.strip! unless NO_STRIP.include?(match.name)
284:             unless match_with.is_a?(Regexp) ? (html =~ match_with) : (html == match_with.to_s)
285:               content_mismatch ||= build_message(message, "<?> expected but was\n<?>.", match_with, html)
286:               true
287:             end
288:           end
289:         end
290:         # Expecting foo found bar element only if found zero, not if
291:         # found one but expecting two.
292:         message ||= content_mismatch if matches.empty?
293:         # Test minimum/maximum occurrence.
294:         min, max = equals[:minimum], equals[:maximum]
295:         message = message || %(Expected #{count_description(min, max)} matching "#{selector.to_s}", found #{matches.size}.)
296:         assert matches.size >= min, message if min
297:         assert matches.size <= max, message if max
298:
299:         # If a block is given call that block. Set @selected to allow
300:         # nested assert_select, which can be nested several levels deep.
301:         if block_given? && !matches.empty?
302:           begin
303:             in_scope, @selected = @selected, matches
304:             yield matches
305:           ensure
306:             @selected = in_scope
307:           end
308:         end
309:
310:         # Returns all matches elements.
311:         matches
312:       end
assert_select_email { }

Extracts the body of an email and runs nested assertions on it.

You must enable deliveries for this assertion to work, use:

  ActionMailer::Base.perform_deliveries = true

Examples

 assert_select_email do
   assert_select "h1", "Email alert"
 end

 assert_select_email do
   items = assert_select "ol>li"
   items.each do
      # Work with items here...
   end
 end

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 561
561:       def assert_select_email(&block)
562:         deliveries = ActionMailer::Base.deliveries
563:         assert !deliveries.empty?, "No e-mail in delivery list"
564:
565:         for delivery in deliveries
566:           for part in delivery.parts
567:             if part["Content-Type"].to_s =~ /^text\/html\W/
568:               root = HTML::Document.new(part.body).root
569:               assert_select root, ":root", &block
570:             end
571:           end
572:         end
573:       end
assert_select_encoded(element?) { |elements| ... }

Extracts the content of an element, treats it as encoded HTML and runs nested assertion on it.

You typically call this method within another assertion to operate on all currently selected elements. You can also pass an element or array of elements.

The content of each element is un-encoded, and wrapped in the root element encoded. It then calls the block with all un-encoded elements.

Examples

  # Selects all bold tags from within the title of an ATOM feed's entries (perhaps to nab a section name prefix)
  assert_select_feed :atom, 1.0 do
    # Select each entry item and then the title item
    assert_select "entry>title" do
      # Run assertions on the encoded title elements
      assert_select_encoded do
        assert_select "b"
      end
    end
  end

  # Selects all paragraph tags from within the description of an RSS feed
  assert_select_feed :rss, 2.0 do
    # Select description element of each feed item.
    assert_select "channel>item>description" do
      # Run assertions on the encoded elements.
      assert_select_encoded do
        assert_select "p"
      end
    end
  end

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 507
507:       def assert_select_encoded(element = nil, &block)
508:         case element
509:           when Array
510:             elements = element
511:           when HTML::Node
512:             elements = [element]
513:           when nil
514:             unless elements = @selected
515:               raise ArgumentError, "First argument is optional, but must be called from a nested assert_select"
516:             end
517:           else
518:             raise ArgumentError, "Argument is optional, and may be node or array of nodes"
519:         end
520:
521:         fix_content = lambda do |node|
522:           # Gets around a bug in the Rails 1.1 HTML parser.
523:           node.content.gsub(/<!\[CDATA\[(.*)(\]\]>)?/m) { CGI.escapeHTML($1) }
524:         end
525:
526:         selected = elements.map do |element|
527:           text = element.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join
528:           root = HTML::Document.new(CGI.unescapeHTML("<encoded>#{text}</encoded>")).root
529:           css_select(root, "encoded:root", &block)[0]
530:         end
531:
532:         begin
533:           old_selected, @selected = @selected, selected
534:           assert_select ":root", &block
535:         ensure
536:           @selected = old_selected
537:         end
538:       end
assert_select_rjs(id?) { |elements| ... }
assert_select_rjs(statement, id?) { |elements| ... }
assert_select_rjs(:insert, position, id?) { |elements| ... }

Selects content from the RJS response.

Narrowing down

With no arguments, asserts that one or more elements are updated or inserted by RJS statements.

Use the id argument to narrow down the assertion to only statements that update or insert an element with that identifier.

Use the first argument to narrow down assertions to only statements of that type. Possible values are :replace, :replace_html, :show, :hide, :toggle, :remove and :insert_html.

Use the argument :insert followed by an insertion position to narrow down the assertion to only statements that insert elements in that position. Possible values are :top, :bottom, :before and :after.

Using the :remove statement, you will be able to pass a block, but it will be ignored as there is no HTML passed for this statement.

Using blocks

Without a block, assert_select_rjs merely asserts that the response contains one or more RJS statements that replace or update content.

With a block, assert_select_rjs also selects all elements used in these statements and passes them to the block. Nested assertions are supported.

Calling assert_select_rjs with no arguments and using nested asserts asserts that the HTML content is returned by one or more RJS statements. Using assert_select directly makes the same assertion on the content, but without distinguishing whether the content is returned in an HTML or JavaScript.

Examples

  # Replacing the element foo.
  # page.replace 'foo', ...
  assert_select_rjs :replace, "foo"

  # Replacing with the chained RJS proxy.
  # page[:foo].replace ...
  assert_select_rjs :chained_replace, 'foo'

  # Inserting into the element bar, top position.
  assert_select_rjs :insert, :top, "bar"

  # Remove the element bar
  assert_select_rjs :remove, "bar"

  # Changing the element foo, with an image.
  assert_select_rjs "foo" do
    assert_select "img[src=/images/logo.gif""
  end

  # RJS inserts or updates a list with four items.
  assert_select_rjs do
    assert_select "ol>li", 4
  end

  # The same, but shorter.
  assert_select "ol>li", 4

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 397
397:       def assert_select_rjs(*args, &block)
398:         rjs_type = nil
399:         arg      = args.shift
400:
401:         # If the first argument is a symbol, it's the type of RJS statement we're looking
402:         # for (update, replace, insertion, etc). Otherwise, we're looking for just about
403:         # any RJS statement.
404:         if arg.is_a?(Symbol)
405:           rjs_type = arg
406:
407:           if rjs_type == :insert
408:             arg = args.shift
409:             insertion = "insert_#{arg}".to_sym
410:             raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
411:             statement = "(#{RJS_STATEMENTS[insertion]})"
412:           else
413:             raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
414:             statement = "(#{RJS_STATEMENTS[rjs_type]})"
415:           end
416:           arg = args.shift
417:         else
418:           statement = "#{RJS_STATEMENTS[:any]}"
419:         end
420:
421:         # Next argument we're looking for is the element identifier. If missing, we pick
422:         # any element.
423:         if arg.is_a?(String)
424:           id = Regexp.quote(arg)
425:           arg = args.shift
426:         else
427:           id = "[^\"]*"
428:         end
429:
430:         pattern =
431:           case rjs_type
432:             when :chained_replace, :chained_replace_html
433:               Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
434:             when :remove, :show, :hide, :toggle
435:               Regexp.new("#{statement}\\(\"#{id}\"\\)")
436:             else
437:               Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
438:           end
439:
440:         # Duplicate the body since the next step involves destroying it.
441:         matches = nil
442:         case rjs_type
443:           when :remove, :show, :hide, :toggle
444:             matches = @response.body.match(pattern)
445:           else
446:             @response.body.gsub(pattern) do |match|
447:               html = unescape_rjs($2)
448:               matches ||= []
449:               matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
450:               ""
451:             end
452:         end
453:
454:         if matches
455:           assert_block("") { true } # to count the assertion
456:           if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type)
457:             begin
458:               in_scope, @selected = @selected, matches
459:               yield matches
460:             ensure
461:               @selected = in_scope
462:             end
463:           end
464:           matches
465:         else
466:           # RJS statement not found.
467:           flunk args.shift || "No RJS statement that replaces or inserts HTML content."
468:         end
469:       end
css_select(selector) => array
css_select(element, selector) => array

Select and return all matching elements.

If called with a single argument, uses that argument as a selector to match all elements of the current page. Returns an empty array if no match is found.

If called with two arguments, uses the first argument as the base element and the second argument as the selector. Attempts to match the base element and any of its children. Returns an empty array if no match is found.

The selector may be a CSS selector expression (String), an expression with substitution values (Array) or an HTML::Selector object.

Examples

  # Selects all div tags
  divs = css_select("div")

  # Selects all paragraph tags and does something interesting
  pars = css_select("p")
  pars.each do |par|
    # Do something fun with paragraphs here...
  end

  # Selects all list items in unordered lists
  items = css_select("ul>li")

  # Selects all form tags and then all inputs inside the form
  forms = css_select("form")
  forms.each do |form|
    inputs = css_select(form, "input")
    ...
  end

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 70
 70:       def css_select(*args)
 71:         # See assert_select to understand what's going on here.
 72:         arg = args.shift
 73:
 74:         if arg.is_a?(HTML::Node)
 75:           root = arg
 76:           arg = args.shift
 77:         elsif arg == nil
 78:           raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?"
 79:         elsif @selected
 80:           matches = []
 81:
 82:           @selected.each do |selected|
 83:             subset = css_select(selected, HTML::Selector.new(arg.dup, args.dup))
 84:             subset.each do |match|
 85:               matches << match unless matches.any? { |m| m.equal?(match) }
 86:             end
 87:           end
 88:
 89:           return matches
 90:         else
 91:           root = response_from_page_or_rjs
 92:         end
 93:
 94:         case arg
 95:           when String
 96:             selector = HTML::Selector.new(arg, args)
 97:           when Array
 98:             selector = HTML::Selector.new(*arg)
 99:           when HTML::Selector
100:             selector = arg
101:           else raise ArgumentError, "Expecting a selector as the first argument"
102:         end
103:
104:         selector.select(root)
105:       end
Protected Instance methods
response_from_page_or_rjs()

assert_select and css_select call this to obtain the content in the HTML page, or from all the RJS statements, depending on the type of response.

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 603
603:         def response_from_page_or_rjs()
604:           content_type = @response.content_type
605:
606:           if content_type && content_type =~ /text\/javascript/
607:             body = @response.body.dup
608:             root = HTML::Node.new(nil)
609:
610:             while true
611:               next if body.sub!(RJS_PATTERN_EVERYTHING) do |match|
612:                 html = unescape_rjs($3)
613:                 matches = HTML::Document.new(html).root.children.select { |n| n.tag? }
614:                 root.children.concat matches
615:                 ""
616:               end
617:               break
618:             end
619:
620:             root
621:           else
622:             html_document.root
623:           end
624:         end
unescape_rjs(rjs_string)

Unescapes a RJS string.

[ show source ]

     # File actionpack/lib/action_controller/assertions/selector_assertions.rb, line 627
627:         def unescape_rjs(rjs_string)
628:           # RJS encodes double quotes and line breaks.
629:           unescaped= rjs_string.gsub('\"', '"')
630:           unescaped.gsub!(/\\\//, '/')
631:           unescaped.gsub!('\n', "\n")
632:           unescaped.gsub!('\076', '>')
633:           unescaped.gsub!('\074', '<')
634:           # RJS encodes non-ascii characters.
635:           unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')}
636:           unescaped
637:         end


Module: ActionController::Assertions::TagAssertions

Module
ActionController::Assertions::TagAssertions
In: actionpack/lib/action_controller/assertions/tag_assertions.rb

Pair of assertions to testing elements in the HTML output of the response.

Methods
  • assert_no_tag
  • assert_tag
Public Instance methods
assert_no_tag(*opts)

Identical to assert_tag, but asserts that a matching tag does not exist. (See assert_tag for a full discussion of the syntax.)

Examples

  # Assert that there is not a "div" containing a "p"
  assert_no_tag :tag => "div", :descendant => { :tag => "p" }

  # Assert that an unordered list is empty
  assert_no_tag :tag => "ul", :descendant => { :tag => "li" }

  # Assert that there is not a "p" tag with between 1 to 3 "img" tags
  # as immediate children
  assert_no_tag :tag => "p",
             :children => { :count => 1..3, :only => { :tag => "img" } }

[ show source ]

     # File actionpack/lib/action_controller/assertions/tag_assertions.rb, line 121
121:       def assert_no_tag(*opts)
122:         clean_backtrace do
123:           opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first
124:           tag = find_tag(opts)
125:           assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}"
126:         end
127:       end
assert_tag(*opts)

Asserts that there is a tag/node/element in the body of the response that meets all of the given conditions. The conditions parameter must be a hash of any of the following keys (all are optional):

  • :tag: the node type must match the corresponding value
  • :attributes: a hash. The node‘s attributes must match the corresponding values in the hash.
  • :parent: a hash. The node‘s parent must match the corresponding hash.
  • :child: a hash. At least one of the node‘s immediate children must meet the criteria described by the hash.
  • :ancestor: a hash. At least one of the node‘s ancestors must meet the criteria described by the hash.
  • :descendant: a hash. At least one of the node‘s descendants must meet the criteria described by the hash.
  • :sibling: a hash. At least one of the node‘s siblings must meet the criteria described by the hash.
  • :after: a hash. The node must be after any sibling meeting the criteria described by the hash, and at least one sibling must match.
  • :before: a hash. The node must be before any sibling meeting the criteria described by the hash, and at least one sibling must match.
  • :children: a hash, for counting children of a node. Accepts the keys:
    • :count: either a number or a range which must equal (or include) the number of children that match.
    • :less_than: the number of matching children must be less than this number.
    • :greater_than: the number of matching children must be greater than this number.
    • :only: another hash consisting of the keys to use to match on the children, and only matching children will be counted.
  • :content: the textual content of the node must match the given value. This will not match HTML tags in the body of a tag—only text.

Conditions are matched using the following algorithm:

  • if the condition is a string, it must be a substring of the value.
  • if the condition is a regexp, it must match the value.
  • if the condition is a number, the value must match number.to_s.
  • if the condition is true, the value must not be nil.
  • if the condition is false or nil, the value must be nil.

Examples

  # Assert that there is a "span" tag
  assert_tag :tag => "span"

  # Assert that there is a "span" tag with id="x"
  assert_tag :tag => "span", :attributes => { :id => "x" }

  # Assert that there is a "span" tag using the short-hand
  assert_tag :span

  # Assert that there is a "span" tag with id="x" using the short-hand
  assert_tag :span, :attributes => { :id => "x" }

  # Assert that there is a "span" inside of a "div"
  assert_tag :tag => "span", :parent => { :tag => "div" }

  # Assert that there is a "span" somewhere inside a table
  assert_tag :tag => "span", :ancestor => { :tag => "table" }

  # Assert that there is a "span" with at least one "em" child
  assert_tag :tag => "span", :child => { :tag => "em" }

  # Assert that there is a "span" containing a (possibly nested)
  # "strong" tag.
  assert_tag :tag => "span", :descendant => { :tag => "strong" }

  # Assert that there is a "span" containing between 2 and 4 "em" tags
  # as immediate children
  assert_tag :tag => "span",
             :children => { :count => 2..4, :only => { :tag => "em" } }

  # Get funky: assert that there is a "div", with an "ul" ancestor
  # and an "li" parent (with "class" = "enum"), and containing a
  # "span" descendant that contains text matching /hello world/
  assert_tag :tag => "div",
             :ancestor => { :tag => "ul" },
             :parent => { :tag => "li",
                          :attributes => { :class => "enum" } },
             :descendant => { :tag => "span",
                              :child => /hello world/ }

Please note: assert_tag and assert_no_tag only work with well-formed XHTML. They recognize a few tags as implicitly self-closing (like br and hr and such) but will not work correctly with tags that allow optional closing tags (p, li, td). You must explicitly close all of your tags to use these assertions.

[ show source ]

     # File actionpack/lib/action_controller/assertions/tag_assertions.rb, line 99
 99:       def assert_tag(*opts)
100:         clean_backtrace do
101:           opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first
102:           tag = find_tag(opts)
103:           assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}"
104:         end
105:       end


Module: ActionController::Benchmarking::ClassMethods

Module
ActionController::Benchmarking::ClassMethods
In: actionpack/lib/action_controller/benchmarking.rb
Methods
  • benchmark
  • silence
Public Instance methods
benchmark(title, log_level = Logger::DEBUG, use_silence = true) {|| ...}

Log and benchmark the workings of a single block and silence whatever logging that may have happened inside it (unless use_silence is set to false).

The benchmark is only recorded if the current level of the logger matches the log_level, which makes it easy to include benchmarking statements in production software that will remain inexpensive because the benchmark will only be conducted if the log level is low enough.

[ show source ]

    # File actionpack/lib/action_controller/benchmarking.rb, line 23
23:       def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
24:         if logger && logger.level == log_level
25:           result = nil
26:           seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
27:           logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
28:           result
29:         else
30:           yield
31:         end
32:       end
silence() {|| ...}

Silences the logger for the duration of the block.

[ show source ]

    # File actionpack/lib/action_controller/benchmarking.rb, line 35
35:       def silence
36:         old_logger_level, logger.level = logger.level, Logger::ERROR if logger
37:         yield
38:       ensure
39:         logger.level = old_logger_level if logger
40:       end


Module: ActionController::Caching

Module
ActionController::Caching
In: actionpack/lib/action_controller/caching.rb

Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls around for subsequent requests. Action Controller affords you three approaches in varying levels of granularity: Page, Action, Fragment.

You can read more about each approach and the sweeping assistance by clicking the modules below.

Note: To turn off all caching and sweeping, set Base.perform_caching = false.

Included Modules
  • Pages
  • Actions
  • Fragments
  • Sweeping
  • SqlCache
Classes and Modules
Module ActionController::Caching::Actions
Module ActionController::Caching::Fragments
Module ActionController::Caching::Pages
Module ActionController::Caching::SqlCache
Module ActionController::Caching::Sweeping


Module: ActionController::Caching::Actions

Module
ActionController::Caching::Actions
In: actionpack/lib/action_controller/caching.rb

Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching, every request still goes through the Action Pack. The key benefit of this is that filters are run before the cache is served, which allows for authentication and other restrictions on whether someone is allowed to see the cache. Example:

  class ListsController < ApplicationController
    before_filter :authenticate, :except => :public
    caches_page   :public
    caches_action :show, :feed
  end

In this example, the public action doesn‘t require authentication, so it‘s possible to use the faster page caching method. But both the show and feed action are to be shielded behind the authenticate filter, so we need to implement those as action caches.

Action caching internally uses the fragment caching and an around filter to do the job. The fragment cache is named according to both the current host and the path. So a page that is accessed at david.somewhere.com/lists/show/1 will result in a fragment named "david.somewhere.com/lists/show/1". This allows the cacher to differentiate between "david.somewhere.com/lists/" and "jamis.somewhere.com/lists/" — which is a helpful way of assisting the subdomain-as-account-key pattern.

Different representations of the same resource, e.g. david.somewhere.com/lists and david.somewhere.com/lists.xml are treated like separate requests and so are cached separately. Keep in mind when expiring an action cache that :action => ‘lists‘ is not the same as :action => ‘list’, :format => :xml.

You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.

  class ListsController < ApplicationController
    before_filter :authenticate, :except => :public
    caches_page   :public
    caches_action :show, :cache_path => { :project => 1 }
    caches_action :show, :cache_path => Proc.new { |controller|
      controller.params[:user_id] ?
        controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
        controller.send(:list_url, c.params[:id]) }
  end
Methods
  • expire_action
  • protected_instance_variables_with_action_caching
Classes and Modules
Module ActionController::Caching::Actions::ClassMethods
Class ActionController::Caching::Actions::ActionCachePath
Public Instance methods
expire_action(options = {})

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 217
217:       def expire_action(options = {})
218:         return unless perform_caching
219:         if options[:action].is_a?(Array)
220:           options[:action].dup.each do |action|
221:             expire_fragment(ActionCachePath.path_for(self, options.merge({ :action => action })))
222:           end
223:         else
224:           expire_fragment(ActionCachePath.path_for(self, options))
225:         end
226:       end
protected_instance_variables_with_action_caching()

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 213
213:       def protected_instance_variables_with_action_caching
214:         protected_instance_variables_without_action_caching + %w(@action_cache_path)
215:       end


Class: ActionController::Caching::Actions::ActionCachePath

Class
ActionController::Caching::Actions::ActionCachePath
In: | actionpack/lib/action_controller/caching.rb
Parent: | Object
Methods
  • new
  • path_for
Attributes
[R] | extension
[R] | path
Public Class methods
new(controller, options = {})

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 275
275:         def initialize(controller, options = {})
276:           @extension = extract_extension(controller.request.path)
277:           path = controller.url_for(options).split('://').last
278:           normalize!(path)
279:           add_extension!(path, @extension)
280:           @path = URI.unescape(path)
281:         end
path_for(controller, options)

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 270
270:           def path_for(controller, options)
271:             new(controller, options).path
272:           end


Module: ActionController::Caching::Actions::ClassMethods

Module
ActionController::Caching::Actions::ClassMethods
In: actionpack/lib/action_controller/caching.rb
Methods
  • caches_action
Public Instance methods
caches_action(*actions)

Declares that actions should be cached. See ActionController::Caching::Actions for details.

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 207
207:         def caches_action(*actions)
208:           return unless perform_caching
209:           around_filter(ActionCacheFilter.new(*actions))
210:         end


Module: ActionController::Caching::Fragments

Module
ActionController::Caching::Fragments
In: actionpack/lib/action_controller/caching.rb

Fragment caching is used for caching various blocks within templates without caching the entire action as a whole. This is useful when certain elements of an action change frequently or depend on complicated state while other parts rarely change or can be shared amongst multiple parties. The caching is doing using the cache helper available in the Action View. A template with caching might look something like:

  <b>Hello <%= @name %></b>
  <% cache do %>
    All the topics in the system:
    <%= render :partial => "topic", :collection => Topic.find(:all) %>
  <% end %>

This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would be able to invalidate it using expire_fragment(:controller => "topics", :action => "list").

This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using caches_action, so we also have the option to qualify the name of the cached fragment with something like:

  <% cache(:action => "list", :action_suffix => "all_topics") do %>

That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a different suffix. Note that the URL doesn‘t have to really exist or be callable - the url_for system is just used to generate unique cache names that we can refer to when we need to expire the cache.

The expiration call for this example is:

  expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics")

Fragment stores

By default, cached fragments are stored in memory. The available store options are:

  • FileStore: Keeps the fragments on disk in the cache_path, which works well for all types of environments and allows all processes running from the same application directory to access the cached content.
  • MemoryStore: Keeps the fragments in memory, which is fine for WEBrick and for FCGI (if you don‘t care that each FCGI process holds its own fragment store). It‘s not suitable for CGI as the process is thrown away at the end of each request. It can potentially also take up a lot of memory since each process keeps all the caches in memory.
  • DRbStore: Keeps the fragments in the memory of a separate, shared DRb process. This works for all environments and only keeps one cache around for all processes, but requires that you run and manage a separate DRb process.
  • MemCacheStore: Works like DRbStore, but uses Danga‘s MemCache instead. Requires the ruby-memcache library: gem install ruby-memcache.

Configuration examples (MemoryStore is the default):

  ActionController::Base.fragment_cache_store = :memory_store
  ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory"
  ActionController::Base.fragment_cache_store = :drb_store, "druby://localhost:9192"
  ActionController::Base.fragment_cache_store = :mem_cache_store, "localhost"
  ActionController::Base.fragment_cache_store = MyOwnStore.new("parameter")
Methods
  • cache_erb_fragment
  • expire_fragment
  • fragment_cache_key
  • fragment_cache_store=
  • read_fragment
  • write_fragment
Public Class methods
fragment_cache_store=(store_option)

Defines the storage option for cached fragments

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 354
354:           def self.fragment_cache_store=(store_option)
355:             store, *parameters = *([ store_option ].flatten)
356:             @@fragment_cache_store = if store.is_a?(Symbol)
357:               store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize)
358:               store_class = ActionController::Caching::Fragments.const_get(store_class_name)
359:               store_class.new(*parameters)
360:             else
361:               store
362:             end
363:           end
Public Instance methods
cache_erb_fragment(block, name = {}, options = nil)

Called by CacheHelper#cache

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 375
375:       def cache_erb_fragment(block, name = {}, options = nil)
376:         unless perform_caching then block.call; return end
377:
378:         buffer = eval(ActionView::Base.erb_variable, block.binding)
379:
380:         if cache = read_fragment(name, options)
381:           buffer.concat(cache)
382:         else
383:           pos = buffer.length
384:           block.call
385:           write_fragment(name, buffer[pos..-1], options)
386:         end
387:       end
expire_fragment(name, options = nil)

Name can take one of three forms:

  • String: This would normally take the form of a path like "pages/45/notes"
  • Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 }
  • Regexp: Will destroy all the matched fragments, example:
      %r{pages/\d*/notes}

    Ensure you do not specify start and finish in the regex (^$) because the actual filename matched looks like ./cache/filename/path.cache Regexp expiration is only supported on caches that can iterate over all keys (unlike memcached).

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 419
419:       def expire_fragment(name, options = nil)
420:         return unless perform_caching
421:
422:         key = fragment_cache_key(name)
423:
424:         if key.is_a?(Regexp)
425:           self.class.benchmark "Expired fragments matching: #{key.source}" do
426:             fragment_cache_store.delete_matched(key, options)
427:           end
428:         else
429:           self.class.benchmark "Expired fragment: #{key}" do
430:             fragment_cache_store.delete(key, options)
431:           end
432:         end
433:       end
fragment_cache_key(name)

Given a name (as described in expire_fragment), returns a key suitable for use in reading, writing, or expiring a cached fragment. If the name is a hash, the generated name is the return value of url_for on that hash (without the protocol).

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 370
370:       def fragment_cache_key(name)
371:         name.is_a?(Hash) ? url_for(name).split("://").last : name
372:       end
read_fragment(name, options = nil)

Reads a cached fragment from the location signified by name (see expire_fragment for acceptable formats)

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 401
401:       def read_fragment(name, options = nil)
402:         return unless perform_caching
403:
404:         key = fragment_cache_key(name)
405:         self.class.benchmark "Fragment read: #{key}" do
406:           fragment_cache_store.read(key, options)
407:         end
408:       end
write_fragment(name, content, options = nil)

Writes content to the location signified by name (see expire_fragment for acceptable formats)

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 390
390:       def write_fragment(name, content, options = nil)
391:         return unless perform_caching
392:
393:         key = fragment_cache_key(name)
394:         self.class.benchmark "Cached fragment: #{key}" do
395:           fragment_cache_store.write(key, content, options)
396:         end
397:         content
398:       end


Module: ActionController::Caching::Pages

Module
ActionController::Caching::Pages
In: actionpack/lib/action_controller/caching.rb

Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server can serve without going through the Action Pack. This can be as much as 100 times faster than going through the process of dynamically generating the content. Unfortunately, this incredible speed-up is only available to stateless pages where all visitors are treated the same. Content management systems — including weblogs and wikis — have many pages that are a great fit for this approach, but account-based systems where people log in and manipulate their own data are often less likely candidates.

Specifying which actions to cache is done through the caches class method:

  class WeblogController < ActionController::Base
    caches_page :show, :new
  end

This will generate cache files such as weblog/show/5 and weblog/new, which match the URLs used to trigger the dynamic generation. This is how the web server is able pick up a cache file when it exists and otherwise let the request pass on to the Action Pack to generate it.

Expiration of the cache is handled by deleting the cached file, which results in a lazy regeneration approach where the cache is not restored before another hit is made against it. The API for doing so mimics the options from url_for and friends:

  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]
    end
  end

Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be expired.

Setting the cache directory

The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root". For Rails, this directory has already been set to RAILS_ROOT + "/public".

Setting the cache extension

By default, the cache extension is .html, which makes it easy for the cached files to be picked up by the web server. If you want something else, like .php or .shtml, just set Base.page_cache_extension.

Methods
  • cache_page
  • expire_page
Classes and Modules
Module ActionController::Caching::Pages::ClassMethods
Public Instance methods
cache_page(content = nil, options = nil)

Manually cache the content in the key determined by options. If no content is provided, the contents of response.body is used If no options are provided, the requested url is used. Example:

  cache_page "I'm the cached content", :controller => "lists", :action => "show"

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 140
140:       def cache_page(content = nil, options = nil)
141:         return unless perform_caching && caching_allowed
142:
143:         path = case options
144:           when Hash
145:             url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
146:           when String
147:             options
148:           else
149:             request.path
150:         end
151:
152:         self.class.cache_page(content || response.body, path)
153:       end
expire_page(options = {})

Expires the page that was cached with the options as a key. Example:

  expire_page :controller => "lists", :action => "show"

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 121
121:       def expire_page(options = {})
122:         return unless perform_caching
123:
124:         if options.is_a?(Hash)
125:           if options[:action].is_a?(Array)
126:             options[:action].dup.each do |action|
127:               self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action)))
128:             end
129:           else
130:             self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true)))
131:           end
132:         else
133:           self.class.expire_page(options)
134:         end
135:       end


Module: ActionController::Caching::Pages::ClassMethods

Module
ActionController::Caching::Pages::ClassMethods
In: actionpack/lib/action_controller/caching.rb
Methods
  • cache_page
  • caches_page
  • expire_page
Public Instance methods
cache_page(content, path)

Manually cache the content in the key determined by path. Example:

  cache_page "I'm the cached content", "/lists/show"

[ show source ]

    # File actionpack/lib/action_controller/caching.rb, line 90
90:         def cache_page(content, path)
91:           return unless perform_caching
92:
93:           benchmark "Cached page: #{page_cache_file(path)}" do
94:             FileUtils.makedirs(File.dirname(page_cache_path(path)))
95:             File.open(page_cache_path(path), "wb+") { |f| f.write(content) }
96:           end
97:         end
caches_page(*actions)

Caches the actions using the page-caching approach that‘ll store the cache in a path within the page_cache_directory that matches the triggering url.

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 101
101:         def caches_page(*actions)
102:           return unless perform_caching
103:           actions = actions.map(&:to_s)
104:           after_filter { |c| c.cache_page if actions.include?(c.action_name) }
105:         end
expire_page(path)

Expires the page that was cached with the path as a key. Example:

  expire_page "/lists/show"

[ show source ]

    # File actionpack/lib/action_controller/caching.rb, line 80
80:         def expire_page(path)
81:           return unless perform_caching
82:
83:           benchmark "Expired page: #{page_cache_file(path)}" do
84:             File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path))
85:           end
86:         end


Module: ActionController::Caching::SqlCache

Module
ActionController::Caching::SqlCache
In: actionpack/lib/action_controller/caching.rb
Methods
  • perform_action_with_caching
Public Instance methods
perform_action_with_caching()

[ show source ]

     # File actionpack/lib/action_controller/caching.rb, line 676
676:       def perform_action_with_caching
677:         ActiveRecord::Base.cache do
678:           perform_action_without_caching
679:         end
680:       end


Module: ActionController::Caching::Sweeping

Module
ActionController::Caching::Sweeping
In: actionpack/lib/action_controller/caching.rb

Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change. They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:

  class ListSweeper < ActionController::Caching::Sweeper
    observe List, Item

    def after_save(record)
      list = record.is_a?(List) ? record : record.list
      expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
      expire_action(:controller => "lists", :action => "all")
      list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
    end
  end

The sweeper is assigned in the controllers that wish to have its job performed using the cache_sweeper class method:

  class ListsController < ApplicationController
    caches_action :index, :show, :public, :feed
    cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
  end

In the example above, four actions are cached and three actions are responsible for expiring those caches.


Module: ActionController::CgiExt

Module
ActionController::CgiExt
In: actionpack/lib/action_controller/cgi_ext/stdinput.rb
Classes and Modules
Module ActionController::CgiExt::Stdinput


Module: ActionController::CgiExt::Stdinput

Module
ActionController::CgiExt::Stdinput
In: actionpack/lib/action_controller/cgi_ext/stdinput.rb

Publicize the CGI‘s internal input stream so we can lazy-read request.body. Make it writable so we don‘t have to play $stdin games.

Methods
  • included
  • initialize_with_stdinput
Public Class methods
included(base)

[ show source ]

    # File actionpack/lib/action_controller/cgi_ext/stdinput.rb, line 8
 8:       def self.included(base)
 9:         base.class_eval do
10:           remove_method :stdinput
11:           attr_accessor :stdinput
12:         end
13:
14:         base.alias_method_chain :initialize, :stdinput
15:       end
Public Instance methods
initialize_with_stdinput(type = nil, stdinput = $stdin)

[ show source ]

    # File actionpack/lib/action_controller/cgi_ext/stdinput.rb, line 17
17:       def initialize_with_stdinput(type = nil, stdinput = $stdin)
18:         @stdinput = stdinput
19:         initialize_without_stdinput(type || 'query')
20:       end


Class: ActionController::CgiRequest::SessionFixationAttempt

Class
ActionController::CgiRequest::SessionFixationAttempt
In: | actionpack/lib/action_controller/cgi_process.rb
Parent: | StandardError


Module: ActionController::Components

Module
ActionController::Components
In: actionpack/lib/action_controller/components.rb

Components allow you to call other actions for their rendered response while executing another action. You can either delegate the entire response rendering or you can mix a partial response in with your other content.

  class WeblogController < ActionController::Base
    # Performs a method and then lets hello_world output its render
    def delegate_action
      do_other_stuff_before_hello_world
      render_component :controller => "greeter",  :action => "hello_world", :params => { :person => "david" }
    end
  end

  class GreeterController < ActionController::Base
    def hello_world
      render :text => "#{params[:person]} says, Hello World!"
    end
  end

The same can be done in a view to do a partial rendering:

  Let's see a greeting:
  <%= render_component :controller => "greeter", :action => "hello_world" %>

It is also possible to specify the controller as a class constant, bypassing the inflector code to compute the controller class at runtime:

<%= render_component :controller => GreeterController, :action => "hello_world" %>

When to use components

Components should be used with care. They‘re significantly slower than simply splitting reusable parts into partials and conceptually more complicated. Don‘t use components as a way of separating concerns inside a single application. Instead, reserve components to those rare cases where you truly have reusable view and controller elements that can be employed across many applications at once.

So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters.

Methods
  • render_component
Included Modules
  • InstanceMethods
Classes and Modules
Module ActionController::Components::ClassMethods
Module ActionController::Components::InstanceMethods
Public Instance methods
render_component(options)

[ show source ]

    # File actionpack/lib/action_controller/components.rb, line 44
44:           def render_component(options)
45:             @controller.send!(:render_component_as_string, options)
46:           end


Module: ActionController::Components::ClassMethods

Module
ActionController::Components::ClassMethods
In: actionpack/lib/action_controller/components.rb


Module: ActionController::Components::InstanceMethods

Module
ActionController::Components::InstanceMethods
In: actionpack/lib/action_controller/components.rb
Methods
  • render_component
  • render_component_as_string
Protected Instance methods
render_component(options)

Renders the component specified as the response for the current method

[ show source ]

    # File actionpack/lib/action_controller/components.rb, line 79
79:         def render_component(options) #:doc:
80:           component_logging(options) do
81:             render_for_text(component_response(options, true).body, response.headers["Status"])
82:           end
83:         end
render_component_as_string(options)

Returns the component response as a string

[ show source ]

    # File actionpack/lib/action_controller/components.rb, line 86
86:         def render_component_as_string(options) #:doc:
87:           component_logging(options) do
88:             response = component_response(options, false)
89:
90:             if redirected = response.redirected_to
91:               render_component_as_string(redirected)
92:             else
93:               response.body
94:             end
95:           end
96:         end


Module: ActionController::Cookies

Module
ActionController::Cookies
In: actionpack/lib/action_controller/cookies.rb

Cookies are read and written through ActionController#cookies. The cookies being read are what were received along with the request, the cookies being written are what will be sent out with the response. Cookies are read by value (so you won‘t get the cookie object itself back — just the value it holds). Examples for writing:

  cookies[:user_name] = "david" # => Will set a simple session cookie
  cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
  # => Will set a cookie that expires in 1 hour

Examples for reading:

  cookies[:user_name] # => "david"
  cookies.size         # => 2

Example for deleting:

  cookies.delete :user_name

All the option symbols for setting cookies are:

  • value - the cookie‘s value or list of values (as an array).
  • path - the path for which this cookie applies. Defaults to the root of the application.
  • domain - the domain for which this cookie applies.
  • expires - the time at which this cookie expires, as a Time object.
  • secure - whether this cookie is a secure cookie or not (default to false).
                      Secure cookies are only transmitted to HTTPS servers.
  • http_only - whether this cookie is accessible via scripting or only HTTP (defaults to false).
Methods
  • cookies
  • included
Public Class methods
included(base)

[ show source ]

    # File actionpack/lib/action_controller/cookies.rb, line 30
30:     def self.included(base)
31:       base.helper_method :cookies
32:     end
Protected Instance methods
cookies()

Returns the cookie container, which operates as described above.

[ show source ]

    # File actionpack/lib/action_controller/cookies.rb, line 36
36:       def cookies
37:         CookieJar.new(self)
38:       end


Class: ActionController::Dispatcher

Class
ActionController::Dispatcher
In: | actionpack/lib/action_controller/dispatcher.rb
Parent: | Object

Dispatches requests to the appropriate controller and takes care of reloading the app after each request when Dependencies.load? is true.

Methods
  • after_dispatch
  • before_dispatch
  • cleanup_application
  • dispatch
  • dispatch
  • dispatch_cgi
  • failsafe_rescue
  • failsafe_response
  • flush_logger
  • handle_request
  • new
  • prepare_application
  • reload_application
  • run_callbacks
  • to_prepare
Public Class methods
after_dispatch(*method_names, &block)

Declare a block to be called after each dispatch. Run in reverse of the order declared.

[ show source ]

    # File actionpack/lib/action_controller/dispatcher.rb, line 21
21:       def after_dispatch(*method_names, &block)
22:         callbacks[:after].concat method_names
23:         callbacks[:after] << block if block_given?
24:       end
before_dispatch(*method_names, &block)

Declare a block to be called before each dispatch. Run in the order declared.

[ show source ]

    # File actionpack/lib/action_controller/dispatcher.rb, line 14
14:       def before_dispatch(*method_names, &block)
15:         callbacks[:before].concat method_names
16:         callbacks[:before] << block if block_given?
17:       end
dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)

Backward-compatible class method takes CGI-specific args. Deprecated in favor of Dispatcher.new(output, request, response).dispatch.

[ show source ]

    # File actionpack/lib/action_controller/dispatcher.rb, line 8
 8:       def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
 9:         new(output).dispatch_cgi(cgi, session_options)
10:       end
failsafe_response(fallback_output, status, originating_exception = nil) {|| ...}

If the block raises, send status code as a last-ditch response.

[ show source ]

    # File actionpack/lib/action_controller/dispatcher.rb, line 48
48:       def failsafe_response(fallback_output, status, originating_exception = nil)
49:         yield
50:       rescue Exception => exception
51:         begin
52:           log_failsafe_exception(status, originating_exception || exception)
53:           body = failsafe_response_body(status)
54:           fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}"
55:           nil
56:         rescue Exception => failsafe_error # Logger or IO errors
57:           $stderr.puts "Error during failsafe response: #{failsafe_error}"
58:           $stderr.puts "(originally #{originating_exception})" if originating_exception
59:         end
60:       end
new(output, request = nil, response = nil)

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 109
109:     def initialize(output, request = nil, response = nil)
110:       @output, @request, @response = output, request, response
111:     end
to_prepare(identifier = nil, &block)

Add a preparation callback. Preparation callbacks are run before every request in development mode, and before the first request in production mode.

An optional identifier may be supplied for the callback. If provided, to_prepare may be called again with the same identifier to replace the existing callback. Passing an identifier is a suggested practice if the code adding a preparation block may be reloaded.

[ show source ]

    # File actionpack/lib/action_controller/dispatcher.rb, line 34
34:       def to_prepare(identifier = nil, &block)
35:         # Already registered: update the existing callback
36:         if identifier
37:           if callback = callbacks[:prepare].assoc(identifier)
38:             callback[1] = block
39:           else
40:             callbacks[:prepare] << [identifier, block]
41:           end
42:         else
43:           callbacks[:prepare] << block
44:         end
45:       end
Public Instance methods
cleanup_application(force = false)

Cleanup the application by clearing out loaded classes so they can be reloaded on the next request without restarting the server.

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 156
156:     def cleanup_application(force = false)
157:       if Dependencies.load? || force
158:         ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
159:         Dependencies.clear
160:         ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
161:       end
162:     end
dispatch()

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 113
113:     def dispatch
114:       run_callbacks :before
115:       handle_request
116:     rescue Exception => exception
117:       failsafe_rescue exception
118:     ensure
119:       run_callbacks :after, :reverse_each
120:     end
dispatch_cgi(cgi, session_options)

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 122
122:     def dispatch_cgi(cgi, session_options)
123:       if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new }
124:         @request = CgiRequest.new(cgi, session_options)
125:         @response = CgiResponse.new(cgi)
126:         dispatch
127:       end
128:     rescue Exception => exception
129:       failsafe_rescue exception
130:     end
flush_logger()

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 164
164:     def flush_logger
165:       RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)
166:     end
prepare_application(force = false)

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 139
139:     def prepare_application(force = false)
140:       begin
141:         require_dependency 'application' unless defined?(::ApplicationController)
142:       rescue LoadError => error
143:         raise unless error.message =~ /application\.rb/
144:       end
145:
146:       ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
147:
148:       if unprepared || force
149:         run_callbacks :prepare
150:         self.unprepared = false
151:       end
152:     end
reload_application()

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 132
132:     def reload_application
133:       if Dependencies.load?
134:         Routing::Routes.reload
135:         self.unprepared = true
136:       end
137:     end
Protected Instance methods
failsafe_rescue(exception)

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 185
185:       def failsafe_rescue(exception)
186:         self.class.failsafe_response(@output, '500 Internal Server Error', exception) do
187:           if @controller ||= defined?(::ApplicationController) ? ::ApplicationController : Base
188:             @controller.process_with_exception(@request, @response, exception).out(@output)
189:           else
190:             raise exception
191:           end
192:         end
193:       end
handle_request()

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 169
169:       def handle_request
170:         @controller = Routing::Routes.recognize(@request)
171:         @controller.process(@request, @response).out(@output)
172:       end
run_callbacks(kind, enumerator = :each)

[ show source ]

     # File actionpack/lib/action_controller/dispatcher.rb, line 174
174:       def run_callbacks(kind, enumerator = :each)
175:         callbacks[kind].send!(enumerator) do |callback|
176:           case callback
177:           when Proc; callback.call(self)
178:           when String, Symbol; send!(callback)
179:           when Array; callback[1].call(self)
180:           else raise ArgumentError, "Unrecognized callback #{callback.inspect}"
181:           end
182:         end
183:       end


Module: ActionController::Filters::ClassMethods

Module
ActionController::Filters::ClassMethods
In: actionpack/lib/action_controller/filters.rb

Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do authentication, caching, or auditing before the intended action is performed. Or to do localization or output compression after the action has been performed. Filters have access to the request, response, and all the instance variables set by other filters in the chain or by the action (in the case of after filters).

Filter inheritance

Controller inheritance hierarchies share filters downwards, but subclasses can also add or skip filters without affecting the superclass. For example:

  class BankController < ActionController::Base
    before_filter :audit

    private
      def audit
        # record the action and parameters in an audit log
      end
  end

  class VaultController < BankController
    before_filter :verify_credentials

    private
      def verify_credentials
        # make sure the user is allowed into the vault
      end
  end

Now any actions performed on the BankController will have the audit method called before. On the VaultController, first the audit method is called, then the verify_credentials method. If the audit method renders or redirects, then verify_credentials and the intended action are never called.

Filter types

A filter can take one of three forms: method reference (symbol), external class, or inline method (proc). The first is the most common and works by referencing a protected or private method somewhere in the inheritance hierarchy of the controller by use of a symbol. In the bank example above, both BankController and VaultController use this form.

Using an external class makes for more easily reused generic filters, such as output compression. External filter classes are implemented by having a static filter method on any class and then passing this class to the filter method. Example:

  class OutputCompressionFilter
    def self.filter(controller)
      controller.response.body = compress(controller.response.body)
    end
  end

  class NewspaperController < ActionController::Base
    after_filter OutputCompressionFilter
  end

The filter method is passed the controller instance and is hence granted access to all aspects of the controller and can manipulate them as it sees fit.

The inline method (using a proc) can be used to quickly do something small that doesn‘t require a lot of explanation. Or just as a quick test. It works like this:

  class WeblogController < ActionController::Base
    before_filter { |controller| head(400) if controller.params["stop_action"] }
  end

As you can see, the block expects to be passed the controller after it has assigned the request to the internal variables. This means that the block has access to both the request and response objects complete with convenience methods for params, session, template, and assigns. Note: The inline method doesn‘t strictly have to be a block; any object that responds to call and returns 1 or -1 on arity will do (such as a Proc or an Method object).

Please note that around_filters function a little differently than the normal before and after filters with regard to filter types. Please see the section dedicated to around_filters below.

Filter chain ordering

Using before_filter and after_filter appends the specified filters to the existing chain. That‘s usually just fine, but some times you care more about the order in which the filters are executed. When that‘s the case, you can use prepend_before_filter and prepend_after_filter. Filters added by these methods will be put at the beginning of their respective chain and executed before the rest. For example:

  class ShoppingController < ActionController::Base
    before_filter :verify_open_shop

  class CheckoutController < ShoppingController
    prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock

The filter chain for the CheckoutController is now :ensure_items_in_cart, :ensure_items_in_stock, :verify_open_shop. So if either of the ensure filters renders or redirects, we‘ll never get around to see if the shop is open or not.

You may pass multiple filter arguments of each type as well as a filter block. If a block is given, it is treated as the last argument.

Around filters

Around filters wrap an action, executing code both before and after. They may be declared as method references, blocks, or objects responding to filter or to both before and after.

To use a method as an around_filter, pass a symbol naming the Ruby method. Yield (or block.call) within the method to run the action.

  around_filter :catch_exceptions

  private
    def catch_exceptions
      yield
    rescue => exception
      logger.debug "Caught exception! #{exception}"
      raise
    end

To use a block as an around_filter, pass a block taking as args both the controller and the action block. You can‘t call yield directly from an around_filter block; explicitly call the action block instead:

  around_filter do |controller, action|
    logger.debug "before #{controller.action_name}"
    action.call
    logger.debug "after #{controller.action_name}"
  end

To use a filter object with around_filter, pass an object responding to :filter or both :before and :after. With a filter method, yield to the block as above:

  around_filter BenchmarkingFilter

  class BenchmarkingFilter
    def self.filter(controller, &block)
      Benchmark.measure(&block)
    end
  end

With before and after methods:

  around_filter Authorizer.new

  class Authorizer
    # This will run before the action. Redirecting aborts the action.
    def before(controller)
      unless user.authorized?
        redirect_to(login_url)
      end
    end

    # This will run after the action if and only if before did not render or redirect.
    def after(controller)
    end
  end

If the filter has before and after methods, the before method will be called before the action. If before renders or redirects, the filter chain is halted and after will not be run. See Filter Chain Halting below for an example.

Filter chain skipping

Declaring a filter on a base class conveniently applies to its subclasses, but sometimes a subclass should skip some of its superclass’ filters:

  class ApplicationController < ActionController::Base
    before_filter :authenticate
    around_filter :catch_exceptions
  end

  class WeblogController < ApplicationController
    # Will run the :authenticate and :catch_exceptions filters.
  end

  class SignupController < ApplicationController
    # Skip :authenticate, run :catch_exceptions.
    skip_before_filter :authenticate
  end

  class ProjectsController < ApplicationController
    # Skip :catch_exceptions, run :authenticate.
    skip_filter :catch_exceptions
  end

  class ClientsController < ApplicationController
    # Skip :catch_exceptions and :authenticate unless action is index.
    skip_filter :catch_exceptions, :authenticate, :except => :index
  end

Filter conditions

Filters may be limited to specific actions by declaring the actions to include or exclude. Both options accept single actions (:only => :index) or arrays of actions (:except => [:foo, :bar]).

  class Journal < ActionController::Base
    # Require authentication for edit and delete.
    before_filter :authorize, :only => [:edit, :delete]

    # Passing options to a filter with a block.
    around_filter(:except => :index) do |controller, action_block|
      results = Profiler.run(&action_block)
      controller.response.sub! "</body>", "#{results}</body>"
    end

    private
      def authorize
        # Redirect to login unless authenticated.
      end
  end

Filter Chain Halting

before_filter and around_filter may halt the request before a controller action is run. This is useful, for example, to deny access to unauthenticated users or to redirect from http to https. Simply call render or redirect. After filters will not be executed if the filter chain is halted.

Around filters halt the request unless the action block is called. Given these filters

  after_filter :after
  around_filter :around
  before_filter :before

The filter chain will look like:

  ...
  .      #   .  #around (code before yield)
  .  .       #   .  .  #before (actual filter code is run)
  .  .  .       #   .  .  .  execute controller action
  .  .  .  /
  .  .  ...
  .  .  /
  .  #around (code after yield)
  . /
  #after (actual filter code is run, unless the around filter does not yield)

If around returns before yielding, after will still not be run. The before filter and controller action will not be run. If before renders or redirects, the second half of around and will still run but after and the action will not. If around fails to yield, after will not be run.

Methods
  • after_filter
  • append_after_filter
  • append_around_filter
  • append_before_filter
  • append_filter_to_chain
  • around_filter
  • before_filter
  • condition_hash
  • filter_chain
  • find_filter_append_position
  • find_filter_prepend_position
  • find_or_create_filter
  • prepend_after_filter
  • prepend_around_filter
  • prepend_before_filter
  • prepend_filter_to_chain
  • remove_actions_from_included_actions!
  • skip_after_filter
  • skip_before_filter
  • skip_filter
  • update_conditions
  • update_filter_chain
Public Instance methods
after_filter(*filters, &block)

Alias for append_after_filter

append_after_filter(*filters, &block)

The passed filters will be appended to the array of filters that run after actions on this controller are performed.

This method is also aliased as after_filter

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 265
265:       def append_after_filter(*filters, &block)
266:         append_filter_to_chain(filters, :after, &block)
267:       end
append_around_filter(*filters, &block)

If you append_around_filter A.new, B.new, the filter chain looks like

  B#before
    A#before
      # run the action
    A#after
  B#after

With around filters which yield to the action block, before and after are the code before and after the yield.

This method is also aliased as around_filter

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 289
289:       def append_around_filter(*filters, &block)
290:         filters, conditions = extract_conditions(filters, &block)
291:         filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter|
292:           append_filter_to_chain([filter, conditions])
293:         end
294:       end
append_before_filter(*filters, &block)

The passed filters will be appended to the filter_chain and will execute before the action on this controller is performed.

This method is also aliased as before_filter

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 250
250:       def append_before_filter(*filters, &block)
251:         append_filter_to_chain(filters, :before, &block)
252:       end
around_filter(*filters, &block)

Alias for append_around_filter

before_filter(*filters, &block)

Alias for append_before_filter

filter_chain()

Returns an array of Filter objects for this controller.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 347
347:       def filter_chain
348:         read_inheritable_attribute("filter_chain") || []
349:       end
prepend_after_filter(*filters, &block)

The passed filters will be prepended to the array of filters that run after actions on this controller are performed.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 271
271:       def prepend_after_filter(*filters, &block)
272:         prepend_filter_to_chain(filters, :after, &block)
273:       end
prepend_around_filter(*filters, &block)

If you prepend_around_filter A.new, B.new, the filter chain looks like:

  A#before
    B#before
      # run the action
    B#after
  A#after

With around filters which yield to the action block, before and after are the code before and after the yield.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 306
306:       def prepend_around_filter(*filters, &block)
307:         filters, conditions = extract_conditions(filters, &block)
308:         filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter|
309:           prepend_filter_to_chain([filter, conditions])
310:         end
311:       end
prepend_before_filter(*filters, &block)

The passed filters will be prepended to the filter_chain and will execute before the action on this controller is performed.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 256
256:       def prepend_before_filter(*filters, &block)
257:         prepend_filter_to_chain(filters, :before, &block)
258:       end
skip_after_filter(*filters)

Removes the specified filters from the after filter chain. Note that this only works for skipping method-reference filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out of many sub-controllers need a different hierarchy.

You can control the actions to skip the filter for with the :only and :except options, just like when you apply the filters.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 332
332:       def skip_after_filter(*filters)
333:         skip_filter_in_chain(*filters, &:after?)
334:       end
skip_before_filter(*filters)

Removes the specified filters from the before filter chain. Note that this only works for skipping method-reference filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out of many sub-controllers need a different hierarchy.

You can control the actions to skip the filter for with the :only and :except options, just like when you apply the filters.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 322
322:       def skip_before_filter(*filters)
323:         skip_filter_in_chain(*filters, &:before?)
324:       end
skip_filter(*filters)

Removes the specified filters from the filter chain. This only works for method reference (symbol) filters, not procs. This method is different from skip_after_filter and skip_before_filter in that it will match any before, after or yielding around filter.

You can control the actions to skip the filter for with the :only and :except options, just like when you apply the filters.

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 342
342:       def skip_filter(*filters)
343:         skip_filter_in_chain(*filters)
344:       end
Protected Instance methods
append_filter_to_chain(filters, filter_type = :around, &block)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 514
514:         def append_filter_to_chain(filters, filter_type = :around, &block)
515:           pos = find_filter_append_position(filters, filter_type)
516:           update_filter_chain(filters, filter_type, pos, &block)
517:         end
condition_hash(filters, *actions)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 618
618:         def condition_hash(filters, *actions)
619:           actions = actions.flatten.map(&:to_s)
620:           filters.inject({}) { |h,f| h.update( f => (actions.blank? ? nil : actions)) }
621:         end
find_filter_append_position(filters, filter_type)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 530
530:         def find_filter_append_position(filters, filter_type)
531:           # appending an after filter puts it at the end of the call chain
532:           # before and around filters go before the first after filter in the chain
533:           unless filter_type == :after
534:             filter_chain.each_with_index do |f,i|
535:               return i if f.after?
536:             end
537:           end
538:           return -1
539:         end
find_filter_prepend_position(filters, filter_type)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 541
541:         def find_filter_prepend_position(filters, filter_type)
542:           # prepending a before or around filter puts it at the front of the call chain
543:           # after filters go before the first after filter in the chain
544:           if filter_type == :after
545:             filter_chain.each_with_index do |f,i|
546:               return i if f.after?
547:             end
548:             return -1
549:           end
550:           return 0
551:         end
find_or_create_filter(filter, filter_type)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 560
560:         def find_or_create_filter(filter, filter_type)
561:           if found_filter = find_filter(filter) { |f| f.type == filter_type }
562:             found_filter
563:           else
564:             f = class_for_filter(filter, filter_type).new(filter)
565:             # apply proxy to filter if necessary
566:             case filter_type
567:             when :before
568:               BeforeFilterProxy.new(f)
569:             when :after
570:               AfterFilterProxy.new(f)
571:             else
572:               f
573:             end
574:           end
575:         end
prepend_filter_to_chain(filters, filter_type = :around, &block)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 519
519:         def prepend_filter_to_chain(filters, filter_type = :around, &block)
520:           pos = find_filter_prepend_position(filters, filter_type)
521:           update_filter_chain(filters, filter_type, pos, &block)
522:         end
remove_actions_from_included_actions!(filters,*actions)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 637
637:         def remove_actions_from_included_actions!(filters,*actions)
638:           actions = actions.flatten.map(&:to_s)
639:           updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter|
640:             ia = (hash[filter] || []) - actions
641:             ia.empty? ? hash.delete(filter) : hash[filter] = ia
642:             hash
643:           end
644:           write_inheritable_attribute('included_actions', updated_hash)
645:         end
update_conditions(filters, conditions)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 609
609:         def update_conditions(filters, conditions)
610:           return if conditions.empty?
611:           if conditions[:only]
612:             write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only]))
613:           elsif conditions[:except]
614:             write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except]))
615:           end
616:         end
update_filter_chain(filters, filter_type, pos, &block)

[ show source ]

     # File actionpack/lib/action_controller/filters.rb, line 524
524:         def update_filter_chain(filters, filter_type, pos, &block)
525:           new_filters = create_filters(filters, filter_type, &block)
526:           new_chain = filter_chain.insert(pos, new_filters).flatten
527:           write_inheritable_attribute('filter_chain', new_chain)
528:         end


Module: ActionController::Flash

Module
ActionController::Flash
In: actionpack/lib/action_controller/flash.rb

The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create action that sets flash[:notice] = "Successfully created" before redirecting to a display action that can then expose the flash to its template. Actually, that exposure is automatically done. Example:

  class WeblogController < ActionController::Base
    def create
      # save post
      flash[:notice] = "Successfully created post"
      redirect_to :action => "display", :params => { :id => post.id }
    end

    def display
      # doesn't need to assign the flash notice to the template, that's done automatically
    end
  end

  display.erb
    <% if flash[:notice] %><div class="notice"><%= flash[:notice] %></div><% end %>

This example just places a string in the flash, but you can put any object in there. And of course, you can put as many as you like at a time too. Just remember: They‘ll be gone by the time the next action has been performed.

See docs on the FlashHash class for more details about the flash.

Methods
  • included
Included Modules
  • InstanceMethods
Classes and Modules
Class ActionController::Flash::FlashHash
Public Class methods
included(base)

[ show source ]

    # File actionpack/lib/action_controller/flash.rb, line 27
27:     def self.included(base)
28:       base.class_eval do
29:         include InstanceMethods
30:         alias_method_chain :assign_shortcuts, :flash
31:         alias_method_chain :process_cleanup,  :flash
32:         alias_method_chain :reset_session,    :flash
33:       end
34:     end


Class: ActionController::Flash::FlashHash

Class
ActionController::Flash::FlashHash
In: | actionpack/lib/action_controller/flash.rb
Parent: | Hash
Methods
  • discard
  • keep
  • now
Public Instance methods
discard(k = nil)

Marks the entire flash or a single flash entry to be discarded by the end of the current action:

    flash.discard              # discard the entire flash at the end of the current action
    flash.discard(:warning)    # discard only the "warning" entry at the end of the current action

[ show source ]

     # File actionpack/lib/action_controller/flash.rb, line 102
102:       def discard(k = nil)
103:         use(k)
104:       end
keep(k = nil)

Keeps either the entire current flash or a specific flash entry available for the next action:

   flash.keep            # keeps the entire flash
   flash.keep(:notice)   # keeps only the "notice" entry, the rest of the flash is discarded

[ show source ]

    # File actionpack/lib/action_controller/flash.rb, line 94
94:       def keep(k = nil)
95:         use(k, false)
96:       end
now()

Sets a flash that will not be available to the next action, only to the current.

    flash.now[:message] = "Hello current action"

This method enables you to use the flash as a central messaging system in your app. When you need to pass an object to the next action, you use the standard flash assign ([]=). When you need to pass an object to the current action, you use now, and your object will vanish when the current action is done.

Entries set via now are accessed the same way as standard entries: flash[‘my-key’].

[ show source ]

    # File actionpack/lib/action_controller/flash.rb, line 86
86:       def now
87:         FlashNow.new(self)
88:       end


Module: ActionController::Helpers::ClassMethods

Module
ActionController::Helpers::ClassMethods
In: actionpack/lib/action_controller/helpers.rb

The Rails framework provides a large number of helpers for working with assets, dates, forms, numbers and ActiveRecord objects, to name a few. These helpers are available to all templates by default.

In addition to using the standard template helpers provided in the Rails framework, creating custom helpers to extract complicated logic or reusable functionality is strongly encouraged. By default, the controller will include a helper whose name matches that of the controller, e.g., MyController will automatically include MyHelper.

Additional helpers can be specified using the helper class method in ActionController::Base or any controller which inherits from it.

Examples

The to_s method from the Time class can be wrapped in a helper method to display a custom message if the Time object is blank:

  module FormattedTimeHelper
    def format_time(time, format=:long, blank_message="&nbsp;")
      time.blank? ? blank_message : time.to_s(format)
    end
  end

FormattedTimeHelper can now be included in a controller, using the helper class method:

  class EventsController < ActionController::Base
    helper FormattedTimeHelper
    def index
      @events = Event.find(:all)
    end
  end

Then, in any view rendered by EventController, the format_time method can be called:

  <% @events.each do |event| -%>
    <p>
      <% format_time(event.time, :short, "N/A") %> | <%= event.name %>
    </p>
  <% end -%>

Finally, assuming we have two event instances, one which has a time and one which does not, the output might look like this:

  23 Aug 11:30 | Carolina Railhawks Soccer Match
  N/A | Carolina Railhaws Training Workshop
Methods
  • helper
  • helper_attr
  • helper_method
Public Instance methods
helper(*args, &block)

The helper class method can take a series of helper module names, a block, or both.

  • *args: One or more Modules, Strings or Symbols, or the special symbol :all.
  • &block: A block defining helper methods.

Examples

When the argument is a String or Symbol, the method will provide the "_helper" suffix, require the file and include the module in the template class. The second form illustrates how to include custom helpers when working with namespaced controllers, or other cases where the file containing the helper definition is not in one of Rails’ standard load paths:

  helper :foo             # => requires 'foo_helper' and includes FooHelper
  helper 'resources/foo'  # => requires 'resources/foo_helper' and includes Resources::FooHelper

When the argument is a Module, it will be included directly in the template class.

  helper FooHelper # => includes FooHelper

When the argument is the symbol :all, the controller will include all helpers from app/helpers/**/*.rb under RAILS_ROOT.

  helper :all

Additionally, the helper class method can receive and evaluate a block, making the methods defined available to the template.

  # One line
  helper { def hello() "Hello, world!" end }
  # Multi-line
  helper do
    def foo(bar)
      "#{bar} is the very best"
    end
  end

Finally, all the above styles can be mixed together, and the helper method can be invoked with a mix of symbols, strings, modules and blocks.

  helper(:three, BlindHelper) { def mice() 'mice' end }

[ show source ]

     # File actionpack/lib/action_controller/helpers.rb, line 110
110:       def helper(*args, &block)
111:         args.flatten.each do |arg|
112:           case arg
113:             when Module
114:               add_template_helper(arg)
115:             when :all
116:               helper(all_application_helpers)
117:             when String, Symbol
118:               file_name  = arg.to_s.underscore + '_helper'
119:               class_name = file_name.camelize
120:
121:               begin
122:                 require_dependency(file_name)
123:               rescue LoadError => load_error
124:                 requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
125:                 if requiree == file_name
126:                   msg = "Missing helper file helpers/#{file_name}.rb"
127:                   raise LoadError.new(msg).copy_blame!(load_error)
128:                 else
129:                   raise
130:                 end
131:               end
132:
133:               add_template_helper(class_name.constantize)
134:             else
135:               raise ArgumentError, "helper expects String, Symbol, or Module argument (was: #{args.inspect})"
136:           end
137:         end
138:
139:         # Evaluate block in template class if given.
140:         master_helper_module.module_eval(&block) if block_given?
141:       end
helper_attr(*attrs)

Declares helper accessors for controller attributes. For example, the following adds new name and name= instance methods to a controller and makes them available to the view:

  helper_attr :name
  attr_accessor :name

[ show source ]

     # File actionpack/lib/action_controller/helpers.rb, line 167
167:       def helper_attr(*attrs)
168:         attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
169:       end
helper_method(*methods)

Declare a controller method as a helper. For example, the following makes the current_user controller method available to the view:

  class ApplicationController < ActionController::Base
    helper_method :current_user
    def current_user
      @current_user ||= User.find(session[:user])
    end
  end

[ show source ]

     # File actionpack/lib/action_controller/helpers.rb, line 151
151:       def helper_method(*methods)
152:         methods.flatten.each do |method|
153:           master_helper_module.module_eval "def \#{method}(*args, &block)\ncontroller.send(%(\#{method}), *args, &block)\nend\n"
154:         end
155:       end


Module: ActionController::HttpAuthentication

Module
ActionController::HttpAuthentication
In: actionpack/lib/action_controller/http_authentication.rb
Classes and Modules
Module ActionController::HttpAuthentication::Basic


Module: ActionController::HttpAuthentication::Basic

Module
ActionController::HttpAuthentication::Basic
In: actionpack/lib/action_controller/http_authentication.rb

Makes it dead easy to do HTTP Basic authentication.

Simple Basic example:

  class PostsController < ApplicationController
    USER_NAME, PASSWORD = "dhh", "secret"

    before_filter :authenticate, :except => [ :index ]

    def index
      render :text => "Everyone can see me!"
    end

    def edit
      render :text => "I'm only accessible if you know the password"
    end

    private
      def authenticate
        authenticate_or_request_with_http_basic do |user_name, password|
          user_name == USER_NAME && password == PASSWORD
        end
      end
  end

Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication, the regular HTML interface is protected by a session approach:

  class ApplicationController < ActionController::Base
    before_filter :set_account, :authenticate

    protected
      def set_account
        @account = Account.find_by_url_name(request.subdomains.first)
      end

      def authenticate
        case request.format
        when Mime::XML, Mime::ATOM
          if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
            @current_user = user
          else
            request_http_basic_authentication
          end
        else
          if session_authenticated?
            @current_user = @account.users.find(session[:authenticated][:user_id])
          else
            redirect_to(login_url) and return false
          end
        end
      end
  end

In your integration tests, you can do something like this:

  def test_access_granted_from_xml
    get(
      "/notes/1.xml", nil,
      :authorization => ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
    )

    assert_equal 200, status
  end

On shared hosts, Apache sometimes doesn‘t pass authentication headers to FCGI instances. If your environment matches this description and you cannot authenticate, try this rule in public/.htaccess (replace the plain one):

  RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
Methods
  • authenticate
  • authentication_request
  • authorization
  • decode_credentials
  • encode_credentials
  • user_name_and_password
Classes and Modules
Module ActionController::HttpAuthentication::Basic::ControllerMethods
Public Instance methods
authenticate(controller, &login_procedure)

[ show source ]

    # File actionpack/lib/action_controller/http_authentication.rb, line 95
95:       def authenticate(controller, &login_procedure)
96:         unless authorization(controller.request).blank?
97:           login_procedure.call(*user_name_and_password(controller.request))
98:         end
99:       end
authentication_request(controller, realm)

[ show source ]

     # File actionpack/lib/action_controller/http_authentication.rb, line 120
120:       def authentication_request(controller, realm)
121:         controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}")
122:         controller.send! :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized
123:       end
authorization(request)

[ show source ]

     # File actionpack/lib/action_controller/http_authentication.rb, line 105
105:       def authorization(request)
106:         request.env['HTTP_AUTHORIZATION']   ||
107:         request.env['X-HTTP_AUTHORIZATION'] ||
108:         request.env['X_HTTP_AUTHORIZATION'] ||
109:         request.env['REDIRECT_X_HTTP_AUTHORIZATION']
110:       end
decode_credentials(request)

[ show source ]

     # File actionpack/lib/action_controller/http_authentication.rb, line 112
112:       def decode_credentials(request)
113:         Base64.decode64(authorization(request).split.last || '')
114:       end
encode_credentials(user_name, password)

[ show source ]

     # File actionpack/lib/action_controller/http_authentication.rb, line 116
116:       def encode_credentials(user_name, password)
117:         "Basic #{Base64.encode64("#{user_name}:#{password}")}"
118:       end
user_name_and_password(request)

[ show source ]

     # File actionpack/lib/action_controller/http_authentication.rb, line 101
101:       def user_name_and_password(request)
102:         decode_credentials(request).split(/:/, 2)
103:       end


Module: ActionController::HttpAuthentication::Basic::ControllerMethods

Module
ActionController::HttpAuthentication::Basic::ControllerMethods
In: actionpack/lib/action_controller/http_authentication.rb
Methods
  • authenticate_or_request_with_http_basic
  • authenticate_with_http_basic
  • request_http_basic_authentication
Public Instance methods
authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)

[ show source ]

    # File actionpack/lib/action_controller/http_authentication.rb, line 82
82:         def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
83:           authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
84:         end
authenticate_with_http_basic(&login_procedure)

[ show source ]

    # File actionpack/lib/action_controller/http_authentication.rb, line 86
86:         def authenticate_with_http_basic(&login_procedure)
87:           HttpAuthentication::Basic.authenticate(self, &login_procedure)
88:         end
request_http_basic_authentication(realm = "Application")

[ show source ]

    # File actionpack/lib/action_controller/http_authentication.rb, line 90
90:         def request_http_basic_authentication(realm = "Application")
91:           HttpAuthentication::Basic.authentication_request(self, realm)
92:         end


Module: ActionController::Integration::Runner

Module
ActionController::Integration::Runner
In: actionpack/lib/action_controller/integration.rb
Methods
  • method_missing
  • open_session
  • reset!
Public Instance methods
method_missing(sym, *args, &block)

Delegate unhandled messages to the current session instance.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 446
446:       def method_missing(sym, *args, &block)
447:         reset! unless @integration_session
448:         returning @integration_session.send!(sym, *args, &block) do
449:           copy_session_variables!
450:         end
451:       end
open_session() {|session if block_given?| ...}

Open a new session instance. If a block is given, the new session is yielded to the block before being returned.

  session = open_session do |sess|
    sess.extend(CustomAssertions)
  end

By default, a single session is automatically created for you, but you can use this method to open multiple sessions that ought to be tested simultaneously.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 413
413:       def open_session
414:         session = Integration::Session.new
415:
416:         # delegate the fixture accessors back to the test instance
417:         extras = Module.new { attr_accessor :delegate, :test_result }
418:         if self.class.respond_to?(:fixture_table_names)
419:           self.class.fixture_table_names.each do |table_name|
420:             name = table_name.tr(".", "_")
421:             next unless respond_to?(name)
422:             extras.send!(:define_method, name) { |*args| delegate.send(name, *args) }
423:           end
424:         end
425:
426:         # delegate add_assertion to the test case
427:         extras.send!(:define_method, :add_assertion) { test_result.add_assertion }
428:         session.extend(extras)
429:         session.delegate = self
430:         session.test_result = @_result
431:
432:         yield session if block_given?
433:         session
434:       end
reset!()

Reset the current session. This is useful for testing multiple sessions in a single test case.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 387
387:       def reset!
388:         @integration_session = open_session
389:       end


Class: ActionController::Integration::Session

Class
ActionController::Integration::Session
In: | actionpack/lib/action_controller/integration.rb
Parent: | Object

An integration Session instance represents a set of requests and responses performed sequentially by some virtual user. Becase you can instantiate multiple sessions and run them side-by-side, you can also mimic (to some limited extent) multiple simultaneous users interacting with your system.

Typically, you will instantiate a new session using IntegrationTest#open_session, rather than instantiating Integration::Session directly.

Methods
  • delete
  • delete_via_redirect
  • follow_redirect!
  • get
  • get_via_redirect
  • head
  • host!
  • https!
  • https?
  • new
  • post
  • post_via_redirect
  • put
  • put_via_redirect
  • redirect?
  • request_via_redirect
  • reset!
  • url_for
  • xhr
  • xml_http_request
Included Modules
  • Test::Unit::Assertions
  • ActionController::Assertions
  • ActionController::TestProcess
  • ControllerCapture
Attributes
[RW] | accept | The Accept header to send.
[R] | controller | A reference to the controller instance used by the last request.
[R] | cookies | A map of the cookies returned by the last response, and which will be sent with the next request.
[R] | headers | A map of the headers returned by the last response.
[RW] | host | The hostname used in the last request.
[R] | path | The URI of the last request.
[RW] | remote_addr | The remote_addr used in the last request.
[R] | request | A reference to the request instance used by the last request.
[RW] | request_count | A running counter of the number of requests processed.
[R] | response | A reference to the response instance used by the last request.
[R] | status | The integer HTTP status code of the last request.
[R] | status_message | The status message that accompanied the status code of the last request.
Public Class methods
new()

Create and initialize a new Session instance.

[ show source ]

    # File actionpack/lib/action_controller/integration.rb, line 58
58:       def initialize
59:         reset!
60:       end
Public Instance methods
delete(path, parameters = nil, headers = nil)

Performs a DELETE request with the given parameters. See get() for more details.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 186
186:       def delete(path, parameters = nil, headers = nil)
187:         process :delete, path, parameters, headers
188:       end
delete_via_redirect(path, parameters = nil, headers = nil)

Performs a DELETE request, following any subsequent redirect. See request_via_redirect() for more information.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 154
154:       def delete_via_redirect(path, parameters = nil, headers = nil)
155:         request_via_redirect(:delete, path, parameters, headers)
156:       end
follow_redirect!()

Follow a single redirect response. If the last response was not a redirect, an exception will be raised. Otherwise, the redirect is performed on the location header.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 118
118:       def follow_redirect!
119:         raise "not a redirect! #{@status} #{@status_message}" unless redirect?
120:         get(interpret_uri(headers['location'].first))
121:         status
122:       end
get(path, parameters = nil, headers = nil)

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). The headers should be a hash. The keys will automatically be upcased, with the prefix ‘HTTP_’ added if needed.

You can also perform POST, PUT, DELETE, and HEAD requests with post, put, delete, and head.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 171
171:       def get(path, parameters = nil, headers = nil)
172:         process :get, path, parameters, headers
173:       end
get_via_redirect(path, parameters = nil, headers = nil)

Performs a GET request, following any subsequent redirect. See request_via_redirect() for more information.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 136
136:       def get_via_redirect(path, parameters = nil, headers = nil)
137:         request_via_redirect(:get, path, parameters, headers)
138:       end
head(path, parameters = nil, headers = nil)

Performs a HEAD request with the given parameters. See get() for more details.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 191
191:       def head(path, parameters = nil, headers = nil)
192:         process :head, path, parameters, headers
193:       end
host!(name)

Set the host name to use in the next request.

  session.host! "www.example.com"

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 111
111:       def host!(name)
112:         @host = name
113:       end
https!(flag=true)

Specify whether or not the session should mimic a secure HTTPS request.

  session.https!
  session.https!(false)

[ show source ]

    # File actionpack/lib/action_controller/integration.rb, line 95
95:       def https!(flag=true)
96:         @https = flag
97:       end
https?()

Return true if the session is mimicing a secure HTTPS request.

  if session.https?
    ...
  end

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 104
104:       def https?
105:         @https
106:       end
post(path, parameters = nil, headers = nil)

Performs a POST request with the given parameters. See get() for more details.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 176
176:       def post(path, parameters = nil, headers = nil)
177:         process :post, path, parameters, headers
178:       end
post_via_redirect(path, parameters = nil, headers = nil)

Performs a POST request, following any subsequent redirect. See request_via_redirect() for more information.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 142
142:       def post_via_redirect(path, parameters = nil, headers = nil)
143:         request_via_redirect(:post, path, parameters, headers)
144:       end
put(path, parameters = nil, headers = nil)

Performs a PUT request with the given parameters. See get() for more details.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 181
181:       def put(path, parameters = nil, headers = nil)
182:         process :put, path, parameters, headers
183:       end
put_via_redirect(path, parameters = nil, headers = nil)

Performs a PUT request, following any subsequent redirect. See request_via_redirect() for more information.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 148
148:       def put_via_redirect(path, parameters = nil, headers = nil)
149:         request_via_redirect(:put, path, parameters, headers)
150:       end
redirect?()

Returns true if the last response was a redirect.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 159
159:       def redirect?
160:         status/100 == 3
161:       end
request_via_redirect(http_method, path, parameters = nil, headers = nil)

Performs a request using the specified method, following any subsequent redirect. Note that the redirects are followed until the response is not a redirect—this means you may run into an infinite loop if your redirect loops back to itself.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 128
128:       def request_via_redirect(http_method, path, parameters = nil, headers = nil)
129:         send(http_method, path, parameters, headers)
130:         follow_redirect! while redirect?
131:         status
132:       end
reset!()

Resets the instance. This can be used to reset the state information in an existing session instance, so it can be used from a clean-slate condition.

  session.reset!

[ show source ]

    # File actionpack/lib/action_controller/integration.rb, line 67
67:       def reset!
68:         @status = @path = @headers = nil
69:         @result = @status_message = nil
70:         @https = false
71:         @cookies = {}
72:         @controller = @request = @response = nil
73:         @request_count = 0
74:
75:         self.host        = "www.example.com"
76:         self.remote_addr = "127.0.0.1"
77:         self.accept      = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
78:
79:         unless defined? @named_routes_configured
80:           # install the named routes in this session instance.
81:           klass = class<<self; self; end
82:           Routing::Routes.install_helpers(klass)
83:
84:           # the helpers are made protected by default--we make them public for
85:           # easier access during testing and troubleshooting.
86:           klass.module_eval { public *Routing::Routes.named_routes.helpers }
87:           @named_routes_configured = true
88:         end
89:       end
url_for(options)

Returns the URL for the given options, according to the rules specified in the application‘s routes.

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 213
213:       def url_for(options)
214:         controller ? controller.url_for(options) : generic_url_rewriter.rewrite(options)
215:       end
xhr(request_method, path, parameters = nil, headers = nil)

Alias for xml_http_request

xml_http_request(request_method, path, parameters = nil, headers = nil)

Performs an XMLHttpRequest request with the given parameters, mirroring a request from the Prototype library.

The request_method is :get, :post, :put, :delete or :head; the parameters are nil, a hash, or a url-encoded or multipart string; the headers are a hash. Keys are automatically upcased and prefixed with ‘HTTP_’ if not already.

This method is also aliased as xhr

[ show source ]

     # File actionpack/lib/action_controller/integration.rb, line 202
202:       def xml_http_request(request_method, path, parameters = nil, headers = nil)
203:         headers ||= {}
204:         headers['X-Requested-With'] = 'XMLHttpRequest'
205:         headers['Accept'] ||= 'text/javascript, text/html, application/xml, text/xml, */*'
206:
207:         process(request_method, path, parameters, headers)
208:       end


Class: ActionController::IntegrationTest

Class
ActionController::IntegrationTest
In: | actionpack/lib/action_controller/integration.rb
Parent: | Test::Unit::TestCase

An IntegrationTest is one that spans multiple controllers and actions, tying them all together to ensure they work together as expected. It tests more completely than either unit or functional tests do, exercising the entire stack, from the dispatcher to the database.

At its simplest, you simply extend IntegrationTest and write your tests using the get/post methods:

  require "#{File.dirname(__FILE__)}/test_helper"

  class ExampleTest < ActionController::IntegrationTest
    fixtures :people

    def test_login
      # get the login page
      get "/login"
      assert_equal 200, status

      # post the login and follow through to the home page
      post "/login", :username => people(:jamis).username,
        :password => people(:jamis).password
      follow_redirect!
      assert_equal 200, status
      assert_equal "/home", path
    end
  end

However, you can also have multiple session instances open per test, and even extend those instances with assertions and methods to create a very powerful testing DSL that is specific for your application. You can even reference any named routes you happen to have defined!

  require "#{File.dirname(__FILE__)}/test_helper"

  class AdvancedTest < ActionController::IntegrationTest
    fixtures :people, :rooms

    def test_login_and_speak
      jamis, david = login(:jamis), login(:david)
      room = rooms(:office)

      jamis.enter(room)
      jamis.speak(room, "anybody home?")

      david.enter(room)
      david.speak(room, "hello!")
    end

    private

      module CustomAssertions
        def enter(room)
          # reference a named route, for maximum internal consistency!
          get(room_url(:id => room.id))
          assert(...)
          ...
        end

        def speak(room, message)
          xml_http_request "/say/#{room.id}", :message => message
          assert(...)
          ...
        end
      end

      def login(who)
        open_session do |sess|
          sess.extend(CustomAssertions)
          who = people(who)
          sess.post "/login", :username => who.username,
            :password => who.password
          assert(...)
        end
      end
  end
Included Modules
  • Integration::Runner


Module: ActionController::Layout::ClassMethods

Module
ActionController::Layout::ClassMethods
In: actionpack/lib/action_controller/layout.rb

Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in repeated setups. The inclusion pattern has pages that look like this:

  <%= render "shared/header" %>
  Hello World
  <%= render "shared/footer" %>

This approach is a decent way of keeping common structures isolated from the changing content, but it‘s verbose and if you ever want to change the structure of these two includes, you‘ll have to change all the templates.

With layouts, you can flip it around and have the common structure know where to insert changing content. This means that the header and footer are only mentioned in one place, like this:

  // The header part of this layout
  <%= yield %>
  // The footer part of this layout -->

And then you have content pages that look like this:

   hello world

Not a word about common structures. At rendering time, the content page is computed and then inserted in the layout, like this:

  // The header part of this layout
  hello world
  // The footer part of this layout -->

Accessing shared variables

Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with references that won‘t materialize before rendering time:

  <h1><%= @page_title %></h1>
  <%= yield %>

…and content pages that fulfill these references at rendering time:

   <% @page_title = "Welcome" %>
   Off-world colonies offers you a chance to start a new life

The result after rendering is:

  <h1>Welcome</h1>
  Off-world colonies offers you a chance to start a new life

Automatic layout assignment

If there is a template in app/views/layouts/ with the same name as the current controller then it will be automatically set as that controller‘s layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named app/views/layouts/weblog.erb or app/views/layouts/weblog.builder exists then it will be automatically set as the layout for your WeblogController. You can create a layout with the name application.erb or application.builder and this will be set as the default controller if there is no layout with the same name as the current controller and there is no layout explicitly assigned with the layout method. Nested controllers use the same folder structure for automatic layout. assignment. So an Admin::WeblogController will look for a template named app/views/layouts/admin/weblog.erb. Setting a layout explicitly will always override the automatic behaviour for the controller where the layout is set. Explicitly setting the layout in a parent class, though, will not override the child class‘s layout assignment if the child class has a layout with the same name.

Inheritance for layouts

Layouts are shared downwards in the inheritance hierarchy, but not upwards. Examples:

  class BankController < ActionController::Base
    layout "bank_standard"

  class InformationController < BankController

  class VaultController < BankController
    layout :access_level_layout

  class EmployeeController < BankController
    layout nil

The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites and picks the layout dynamically, and the EmployeeController doesn‘t want to use a layout at all.

Types of layouts

Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can be done either by specifying a method reference as a symbol or using an inline method (as a proc).

The method reference is the preferred approach to variable layouts and is used like this:

  class WeblogController < ActionController::Base
    layout :writers_and_readers

    def index
      # fetching posts
    end

    private
      def writers_and_readers
        logged_in? ? "writer_layout" : "reader_layout"
      end

Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing is logged in or not.

If you want to use an inline method, such as a proc, do something like this:

  class WeblogController < ActionController::Base
    layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }

Of course, the most common way of specifying a layout is still just as a plain template name:

  class WeblogController < ActionController::Base
    layout "weblog_standard"

If no directory is specified for the template name, the template will by default be looked for in +app/views/layouts/+. Otherwise, it will be looked up relative to the template root.

Conditional layouts

If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The :only and :except options can be passed to the layout call. For example:

  class WeblogController < ActionController::Base
    layout "weblog_standard", :except => :rss

    # ...

  end

This will assign "weblog_standard" as the WeblogController‘s layout except for the rss action, which will not wrap a layout around the rendered view.

Both the :only and :except condition can accept an arbitrary number of method references, so #:except => [ :rss, :text_only ] is valid, as is :except => :rss.

Using a different layout in the action render call

If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. Some times you‘ll have exceptions, though, where one action wants to use a different layout than the rest of the controller. This is possible using the render method. It‘s just a bit more manual work as you‘ll have to supply fully qualified template and layout names as this example shows:

  class WeblogController < ActionController::Base
    def help
      render :action => "help/index", :layout => "help"
    end
  end

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 @content_for_layout instance variable. The preferred notation now is to use yield, as documented above.

Methods
  • layout
Public Instance methods
layout(template_name, conditions = {}, auto = false)

If a layout is specified, all rendered actions will have their result rendered when the layout yields. This layout can itself depend on instance variables assigned during action performance and have access to them as any normal template would.

[ show source ]

     # File actionpack/lib/action_controller/layout.rb, line 171
171:       def layout(template_name, conditions = {}, auto = false)
172:         add_layout_conditions(conditions)
173:         write_inheritable_attribute "layout", template_name
174:         write_inheritable_attribute "auto_layout", auto
175:       end


Module: ActionController::MimeResponds::InstanceMethods

Module
ActionController::MimeResponds::InstanceMethods
In: actionpack/lib/action_controller/mime_responds.rb
Methods
  • respond_to
Public Instance methods
respond_to(*types, &block)

Without web-service support, an action which collects the data for displaying a list of people might look something like this:

  def index
    @people = Person.find(:all)
  end

Here‘s the same action, with web-service support baked in:

  def index
    @people = Person.find(:all)

    respond_to do |format|
      format.html
      format.xml { render :xml => @people.to_xml }
    end
  end

What that says is, "if the client wants HTML in response to this action, just respond as we would have before, but if the client wants XML, return them the list of people in XML format." (Rails determines the desired response format from the HTTP Accept header submitted by the client.)

Supposing you have an action that adds a new person, optionally creating their company (by name) if it does not already exist, without web-services, it might look like this:

  def create
    @company = Company.find_or_create_by_name(params[:company][:name])
    @person  = @company.people.create(params[:person])

    redirect_to(person_list_url)
  end

Here‘s the same action, with web-service support baked in:

  def create
    company  = params[:person].delete(:company)
    @company = Company.find_or_create_by_name(company[:name])
    @person  = @company.people.create(params[:person])

    respond_to do |format|
      format.html { redirect_to(person_list_url) }
      format.js
      format.xml  { render :xml => @person.to_xml(:include => @company) }
    end
  end

If the client wants HTML, we just redirect them back to the person list. If they want Javascript (format.js), then it is an RJS request and we render the RJS template associated with this action. Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also include the person‘s company in the rendered XML, so you get something like this:

  <person>
    <id>...</id>
    ...
    <company>
      <id>...</id>
      <name>...</name>
      ...
    </company>
  </person>

Note, however, the extra bit at the top of that action:

  company  = params[:person].delete(:company)
  @company = Company.find_or_create_by_name(company[:name])

This is because the incoming XML document (if a web-service request is in process) can only contain a single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):

  person[name]=...&person[company][name]=...&...

And, like this (xml-encoded):

  <person>
    <name>...</name>
    <company>
      <name>...</name>
    </company>
  </person>

In other words, we make the request so that it operates on a single entity‘s person. Then, in the action, we extract the company data from the request, find or create the company, and then create the new person with the remaining data.

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

[ show source ]

     # File actionpack/lib/action_controller/mime_responds.rb, line 102
102:       def respond_to(*types, &block)
103:         raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
104:         block ||= lambda { |responder| types.each { |type| responder.send(type) } }
105:         responder = Responder.new(self)
106:         block.call(responder)
107:         responder.respond
108:       end


Class: ActionController::NonInferrableControllerError

Class
ActionController::NonInferrableControllerError
In: | actionpack/lib/action_controller/test_case.rb
Parent: | ActionControllerError
Methods
  • new
Public Class methods
new(name)

[ show source ]

   # File actionpack/lib/action_controller/test_case.rb, line 5
5:     def initialize(name)
6:       super "Unable to determine the controller to test from #{name}. " +
7:         "You'll need to specify it using 'tests YourController' in your " +
8:         "test case definition"
9:     end


Module: ActionController::PolymorphicRoutes

Module
ActionController::PolymorphicRoutes
In: actionpack/lib/action_controller/polymorphic_routes.rb
Methods
  • polymorphic_path
  • polymorphic_url
Public Instance methods
polymorphic_path(record_or_hash_or_array)

[ show source ]

    # File actionpack/lib/action_controller/polymorphic_routes.rb, line 30
30:     def polymorphic_path(record_or_hash_or_array)
31:       polymorphic_url(record_or_hash_or_array, :routing_type => :path)
32:     end
polymorphic_url(record_or_hash_or_array, options = {})

[ show source ]

    # File actionpack/lib/action_controller/polymorphic_routes.rb, line 3
 3:     def polymorphic_url(record_or_hash_or_array, options = {})
 4:       record = extract_record(record_or_hash_or_array)
 5:
 6:       namespace = extract_namespace(record_or_hash_or_array)
 7:
 8:       args = case record_or_hash_or_array
 9:         when Hash;  [ record_or_hash_or_array ]
10:         when Array; record_or_hash_or_array.dup
11:         else        [ record_or_hash_or_array ]
12:       end
13:
14:       inflection =
15:         case
16:         when options[:action] == "new"
17:           args.pop
18:           :singular
19:         when record.respond_to?(:new_record?) && record.new_record?
20:           args.pop
21:           :plural
22:         else
23:           :singular
24:         end
25:
26:       named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
27:       send!(named_route, *args)
28:     end


Module: ActionController::RecordIdentifier

Module
ActionController::RecordIdentifier
In: actionpack/lib/action_controller/record_identifier.rb

The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate the view actions to a higher logical level. Example:

  # routes
  map.resources :posts

  # view
  <% div_for(post) do %>     <div id="post_45" class="post">
    <%= post.body %>           What a wonderful world!
  <% end %>                  </div>

  # controller
  def destroy
    post = Post.find(params[:id])
    post.destroy

    respond_to do |format|
      format.html { redirect_to(post) } # Calls polymorphic_url(post) which in turn calls post_url(post)
      format.js do
        # Calls: new Effect.fade('post_45');
        render(:update) { |page| page[post].visual_effect(:fade) }
      end
    end
  end

As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming convention and allows you to write less code if you follow it.

Methods
  • dom_class
  • dom_id
  • partial_path
  • plural_class_name
  • singular_class_name
Public Instance methods
dom_class(record_or_class, prefix = nil)

The DOM class convention is to use the singular form of an object or class. Examples:

  dom_class(post)   # => "post"
  dom_class(Person) # => "person"

If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:

  dom_class(post, :edit)   # => "edit_post"
  dom_class(Person, :edit) # => "edit_person"

[ show source ]

    # File actionpack/lib/action_controller/record_identifier.rb, line 52
52:     def dom_class(record_or_class, prefix = nil)
53:       [ prefix, singular_class_name(record_or_class) ].compact * '_'
54:     end
dom_id(record, prefix = nil)

The DOM class convention is to use the singular form of an object or class with the id following an underscore. If no id is found, prefix with "new_" instead. Examples:

  dom_class(Post.new(:id => 45)) # => "post_45"
  dom_class(Post.new)            # => "new_post"

If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:

  dom_class(Post.new(:id => 45), :edit) # => "edit_post_45"

[ show source ]

    # File actionpack/lib/action_controller/record_identifier.rb, line 65
65:     def dom_id(record, prefix = nil)
66:       prefix ||= 'new' unless record.id
67:       [ prefix, singular_class_name(record), record.id ].compact * '_'
68:     end
partial_path(record_or_class)

Returns plural/singular for a record or class. Example:

  partial_path(post)   # => "posts/post"
  partial_path(Person) # => "people/person"

[ show source ]

    # File actionpack/lib/action_controller/record_identifier.rb, line 38
38:     def partial_path(record_or_class)
39:       klass = class_from_record_or_class(record_or_class)
40:       "#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
41:     end
plural_class_name(record_or_class)

Returns the plural class name of a record or class. Examples:

  plural_class_name(post)             # => "posts"
  plural_class_name(Highrise::Person) # => "highrise_people"

[ show source ]

    # File actionpack/lib/action_controller/record_identifier.rb, line 74
74:     def plural_class_name(record_or_class)
75:       singular_class_name(record_or_class).pluralize
76:     end
singular_class_name(record_or_class)

Returns the singular class name of a record or class. Examples:

  singular_class_name(post)             # => "post"
  singular_class_name(Highrise::Person) # => "highrise_person"

[ show source ]

    # File actionpack/lib/action_controller/record_identifier.rb, line 82
82:     def singular_class_name(record_or_class)
83:       class_from_record_or_class(record_or_class).name.underscore.tr('/', '_')
84:     end


Module: ActionController::RequestForgeryProtection

Module
ActionController::RequestForgeryProtection
In: actionpack/lib/action_controller/request_forgery_protection.rb
Methods
  • authenticity_token_from_cookie_session
  • authenticity_token_from_session_id
  • form_authenticity_token
  • included
  • protect_against_forgery?
  • verifiable_request_format?
  • verified_request?
  • verify_authenticity_token
Classes and Modules
Module ActionController::RequestForgeryProtection::ClassMethods
Public Class methods
included(base)

[ show source ]

    # File actionpack/lib/action_controller/request_forgery_protection.rb, line 6
 6:     def self.included(base)
 7:       base.class_eval do
 8:         class_inheritable_accessor :request_forgery_protection_options
 9:         self.request_forgery_protection_options = {}
10:         helper_method :form_authenticity_token
11:         helper_method :protect_against_forgery?
12:       end
13:       base.extend(ClassMethods)
14:     end
Protected Instance methods
authenticity_token_from_cookie_session()

No secret was given, so assume this is a cookie session store.

[ show source ]

     # File actionpack/lib/action_controller/request_forgery_protection.rb, line 123
123:       def authenticity_token_from_cookie_session
124:         session[:csrf_id] ||= CGI::Session.generate_unique_id
125:         session.dbman.generate_digest(session[:csrf_id])
126:       end
authenticity_token_from_session_id()

Generates a unique digest using the session_id and the CSRF secret.

[ show source ]

     # File actionpack/lib/action_controller/request_forgery_protection.rb, line 112
112:       def authenticity_token_from_session_id
113:         key = if request_forgery_protection_options[:secret].respond_to?(:call)
114:           request_forgery_protection_options[:secret].call(@session)
115:         else
116:           request_forgery_protection_options[:secret]
117:         end
118:         digest = request_forgery_protection_options[:digest] ||= 'SHA1'
119:         OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(digest), key.to_s, session.session_id.to_s)
120:       end
form_authenticity_token()

Sets the token value for the current session. Pass a :secret option in protect_from_forgery to add a custom salt to the hash.

[ show source ]

     # File actionpack/lib/action_controller/request_forgery_protection.rb, line 99
 99:       def form_authenticity_token
100:         @form_authenticity_token ||= if request_forgery_protection_options[:secret]
101:           authenticity_token_from_session_id
102:         elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest)
103:           authenticity_token_from_cookie_session
104:         elsif session.nil?
105:           raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session.  Use #allow_forgery_protection to disable it, or use a valid session."
106:         else
107:           raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call.  Set that or use a session store capable of generating its own keys (Cookie Session Store)."
108:         end
109:       end
protect_against_forgery?()

[ show source ]

     # File actionpack/lib/action_controller/request_forgery_protection.rb, line 128
128:       def protect_against_forgery?
129:         allow_forgery_protection && request_forgery_protection_token
130:       end
verifiable_request_format?()

[ show source ]

    # File actionpack/lib/action_controller/request_forgery_protection.rb, line 94
94:       def verifiable_request_format?
95:         request.format.html? || request.format.js?
96:       end
verified_request?()

Returns true or false if a request is verified. Checks:

  • is the format restricted? By default, only HTML and AJAX requests are checked.
  • is it a GET request? Gets should be safe and idempotent
  • Does the form_authenticity_token match the given _token value from the params?

[ show source ]

    # File actionpack/lib/action_controller/request_forgery_protection.rb, line 87
87:       def verified_request?
88:         !protect_against_forgery?     ||
89:           request.method == :get      ||
90:           !verifiable_request_format? ||
91:           form_authenticity_token == params[request_forgery_protection_token]
92:       end
verify_authenticity_token()

The actual before_filter that is used. Modify this to change how you handle unverified requests.

[ show source ]

    # File actionpack/lib/action_controller/request_forgery_protection.rb, line 78
78:       def verify_authenticity_token
79:         verified_request? || raise(ActionController::InvalidAuthenticityToken)
80:       end


Module: ActionController::RequestForgeryProtection::ClassMethods

Module
ActionController::RequestForgeryProtection::ClassMethods
In: actionpack/lib/action_controller/request_forgery_protection.rb
Methods
  • protect_from_forgery
Public Instance methods
protect_from_forgery(options = {})

Protect a controller‘s actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a forged link from another site. This is done by embedding a token based on the session (which an attacker wouldn‘t know) in all forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you‘ll have a different authentication scheme there anyway). Also, GET requests are not protected as these should be indempotent anyway.

You turn this on with the protect_from_forgery method, which will perform the check and raise an ActionController::InvalidAuthenticityToken if the token doesn‘t match what was expected. And it will add a _authenticity_token parameter to all forms that are automatically generated by Rails. You can customize the error message given through public/422.html.

Learn more about CSRF (Cross-Site Request Forgery) attacks:

  • isc.sans.org/diary.html?storyid=1750
  • en.wikipedia.org/wiki/Cross-site_request_forgery

Keep in mind, this is NOT a silver-bullet, plug ‘n’ play, warm security blanket for your rails application. There are a few guidelines you should follow:

  • Keep your GET requests safe and idempotent. More reading material:
    • www.xml.com/pub/a/2002/04/24/deviant.html
    • www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
  • Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look for "Expires: at end of session"

If you need to construct a request yourself, but still want to take advantage of forgery protection, you can grab the authenticity_token using the form_authenticity_token helper method and make it part of the parameters yourself.

Example:

  class FooController < ApplicationController
    # uses the cookie session store (then you don't need a separate :secret)
    protect_from_forgery :except => :index

    # uses one of the other session stores that uses a session_id value.
    protect_from_forgery :secret => 'my-little-pony', :except => :index

    # you can disable csrf protection on controller-by-controller basis:
    skip_before_filter :verify_authenticity_token
  end

If you are upgrading from Rails 1.x, disable forgery protection to simplify your tests. Add this to config/environments/test.rb:

  # Disable request forgery protection in test environment
  config.action_controller.allow_forgery_protection = false

Valid Options:

  • :only/:except - passed to the before_filter call. Set which actions are verified.
  • :secret - Custom salt used to generate the form_authenticity_token. Leave this off if you are using the cookie session store.
  • :digest - Message digest used for hashing. Defaults to ‘SHA1‘

[ show source ]

    # File actionpack/lib/action_controller/request_forgery_protection.rb, line 69
69:       def protect_from_forgery(options = {})
70:         self.request_forgery_protection_token ||= :authenticity_token
71:         before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except)
72:         request_forgery_protection_options.update(options)
73:       end


Class: ActionController::RequestProfiler

Class
ActionController::RequestProfiler
In: | actionpack/lib/action_controller/request_profiler.rb
Parent: | Object
Methods
  • benchmark
  • default_options
  • load_ruby_prof
  • new
  • parse_options
  • profile
  • run
  • run
  • show_profile_results
  • warmup
Classes and Modules
Class ActionController::RequestProfiler::Sandbox
Attributes
[R] options
Public Class methods
new(options = {})

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 49
49:     def initialize(options = {})
50:       @options = default_options.merge(options)
51:     end
run(args = nil, options = {})

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 54
54:     def self.run(args = nil, options = {})
55:       profiler = new(options)
56:       profiler.parse_options(args) if args
57:       profiler.run
58:     end
Public Instance methods
benchmark(sandbox)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 81
81:     def benchmark(sandbox)
82:       sandbox.request_count = 0
83:       elapsed = sandbox.benchmark(options[:n]).to_f
84:       count = sandbox.request_count.to_i
85:       puts '%.2f sec, %d requests, %d req/sec' % [elapsed, count, count / elapsed]
86:     end
default_options()

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 92
92:     def default_options
93:       { :n => 100, :open => 'open %s &' }
94:     end
parse_options(args)

Parse command-line options

[ show source ]

     # File actionpack/lib/action_controller/request_profiler.rb, line 97
 97:     def parse_options(args)
 98:       OptionParser.new do |opt|
 99:         opt.banner = "USAGE: #{$0} [options] [session script path]"
100:
101:         opt.on('-n', '--times [0000]', 'How many requests to process. Defaults to 100.') { |v| options[:n] = v.to_i }
102:         opt.on('-b', '--benchmark', 'Benchmark instead of profiling') { |v| options[:benchmark] = v }
103:         opt.on('--open [CMD]', 'Command to open profile results. Defaults to "open %s &"') { |v| options[:open] = v }
104:         opt.on('-h', '--help', 'Show this help') { puts opt; exit }
105:
106:         opt.parse args
107:
108:         if args.empty?
109:           puts opt
110:           exit
111:         end
112:         options[:script] = args.pop
113:       end
114:     end
profile(sandbox)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 72
72:     def profile(sandbox)
73:       load_ruby_prof
74:
75:       results = RubyProf.profile { benchmark(sandbox) }
76:
77:       show_profile_results results
78:       results
79:     end
run()

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 60
60:     def run
61:       sandbox = Sandbox.new(options[:script])
62:
63:       puts 'Warming up once'
64:
65:       elapsed = warmup(sandbox)
66:       puts '%.2f sec, %d requests, %d req/sec' % [elapsed, sandbox.request_count, sandbox.request_count / elapsed]
67:       puts "\n#{options[:benchmark] ? 'Benchmarking' : 'Profiling'} #{options[:n]}x"
68:
69:       options[:benchmark] ? benchmark(sandbox) : profile(sandbox)
70:     end
warmup(sandbox)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 88
88:     def warmup(sandbox)
89:       Benchmark.realtime { sandbox.run }
90:     end
Protected Instance methods
load_ruby_prof()

[ show source ]

     # File actionpack/lib/action_controller/request_profiler.rb, line 117
117:       def load_ruby_prof
118:         begin
119:           require 'ruby-prof'
120:           #RubyProf.measure_mode = RubyProf::ALLOCATED_OBJECTS
121:         rescue LoadError
122:           abort '`gem install ruby-prof` to use the profiler'
123:         end
124:       end
show_profile_results(results)

[ show source ]

     # File actionpack/lib/action_controller/request_profiler.rb, line 126
126:       def show_profile_results(results)
127:         File.open "#{RAILS_ROOT}/tmp/profile-graph.html", 'w' do |file|
128:           RubyProf::GraphHtmlPrinter.new(results).print(file)
129:           `#{options[:open] % file.path}` if options[:open]
130:         end
131:
132:         File.open "#{RAILS_ROOT}/tmp/profile-flat.txt", 'w' do |file|
133:           RubyProf::FlatPrinter.new(results).print(file)
134:           `#{options[:open] % file.path}` if options[:open]
135:         end
136:       end


Class: ActionController::RequestProfiler::Sandbox

Class
ActionController::RequestProfiler::Sandbox
In: | actionpack/lib/action_controller/request_profiler.rb
Parent: | Object

Wrap up the integration session runner.

Methods
  • benchmark
  • benchmark
  • new
  • say
Included Modules
  • Integration::Runner
Public Class methods
benchmark(n, script)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 10
10:       def self.benchmark(n, script)
11:         new(script).benchmark(n)
12:       end
new(script_path)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 14
14:       def initialize(script_path)
15:         @quiet = false
16:         define_run_method(File.read(script_path))
17:         reset!
18:       end
Public Instance methods
benchmark(n)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 20
20:       def benchmark(n)
21:         @quiet = true
22:         print '  '
23:         result = Benchmark.realtime do
24:           n.times do |i|
25:             run
26:             print i % 10 == 0 ? 'x' : '.'
27:             $stdout.flush
28:           end
29:         end
30:         puts
31:         result
32:       ensure
33:         @quiet = false
34:       end
say(message)

[ show source ]

    # File actionpack/lib/action_controller/request_profiler.rb, line 36
36:       def say(message)
37:         puts "  #{message}" unless @quiet
38:       end


Module: ActionController::Rescue

Module
ActionController::Rescue
In: actionpack/lib/action_controller/rescue.rb

Actions that fail to perform as expected throw exceptions. These exceptions can either be rescued for the public view (with a nice user-friendly explanation) or for the developers view (with tons of debugging information). The developers view is already implemented by the Action Controller, but the public view should be tailored to your specific application.

The default behavior for public exceptions is to render a static html file with the name of the error code thrown. If no such file exists, an empty response is sent with the correct status code.

You can override what constitutes a local request by overriding the local_request? method in your own controller. Custom rescue behavior is achieved by overriding the rescue_action_in_public and rescue_action_locally methods.

Methods
  • local_request?
  • log_error
  • render_optional_error_file
  • rescue_action
  • rescue_action_in_public
  • rescue_action_locally
  • rescue_action_with_handler
Classes and Modules
Module ActionController::Rescue::ClassMethods
Constants
LOCALHOST | = | '127.0.0.1'.freeze
DEFAULT_RESCUE_RESPONSE | = | :internal_server_error
DEFAULT_RESCUE_RESPONSES | = | { 'ActionController::RoutingError' => :not_found, 'ActionController::UnknownAction' => :not_found, 'ActiveRecord::RecordNotFound' => :not_found, 'ActiveRecord::StaleObjectError' => :conflict, 'ActiveRecord::RecordInvalid' => :unprocessable_entity, 'ActiveRecord::RecordNotSaved' => :unprocessable_entity, 'ActionController::MethodNotAllowed' => :method_not_allowed, 'ActionController::NotImplemented' => :not_implemented, 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
DEFAULT_RESCUE_TEMPLATE | = | 'diagnostics'
DEFAULT_RESCUE_TEMPLATES | = | { 'ActionController::MissingTemplate' => 'missing_template', 'ActionController::RoutingError' => 'routing_error', 'ActionController::UnknownAction' => 'unknown_action', 'ActionView::TemplateError' => 'template_error'
Protected Instance methods
local_request?(

True if the request came from localhost, 127.0.0.1. Override this method if you wish to redefine the meaning of a local request to include remote IP addresses or other criteria.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 167
167:       def local_request? #:doc:
168:         request.remote_addr == LOCALHOST and request.remote_ip == LOCALHOST
169:       end
log_error(exception)

Overwrite to implement custom logging of errors. By default logs as fatal.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 130
130:       def log_error(exception) #:doc:
131:         ActiveSupport::Deprecation.silence do
132:           if ActionView::TemplateError === exception
133:             logger.fatal(exception.to_s)
134:           else
135:             logger.fatal(
136:               "\n\n#{exception.class} (#{exception.message}):\n    " +
137:               clean_backtrace(exception).join("\n    ") +
138:               "\n\n"
139:             )
140:           end
141:         end
142:       end
render_optional_error_file(status_code)

Attempts to render a static error page based on the status_code thrown, or just return headers if no such file exists. For example, if a 500 error is being handled Rails will first attempt to render the file at public/500.html. If the file doesn‘t exist, the body of the response will be left empty.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 154
154:       def render_optional_error_file(status_code)
155:         status = interpret_status(status_code)
156:         path = "#{RAILS_ROOT}/public/#{status[0,3]}.html"
157:         if File.exist?(path)
158:           render :file => path, :status => status
159:         else
160:           head status
161:         end
162:       end
rescue_action(exception)

Exception handler called when the performance of an action raises an exception.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 112
112:       def rescue_action(exception)
113:         log_error(exception) if logger
114:         erase_results if performed?
115:
116:         # Let the exception alter the response if it wants.
117:         # For example, MethodNotAllowed sets the Allow header.
118:         if exception.respond_to?(:handle_response!)
119:           exception.handle_response!(response)
120:         end
121:
122:         if consider_all_requests_local || local_request?
123:           rescue_action_locally(exception)
124:         else
125:           rescue_action_in_public(exception)
126:         end
127:       end
rescue_action_in_public(exception)

Overwrite to implement public exception handling (for requests answering false to local_request?). By default will call render_optional_error_file. Override this method to provide more user friendly error messages.s

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 146
146:       def rescue_action_in_public(exception) #:doc:
147:         render_optional_error_file response_code_for_rescue(exception)
148:       end
rescue_action_locally(exception)

Render detailed diagnostics for unhandled exceptions rescued from a controller action.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 173
173:       def rescue_action_locally(exception)
174:         add_variables_to_assigns
175:         @template.instance_variable_set("@exception", exception)
176:         @template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
177:         @template.send!(:assign_variables_from_controller)
178:
179:         @template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
180:
181:         response.content_type = Mime::HTML
182:         render_for_file(rescues_path("layout"), response_code_for_rescue(exception))
183:       end
rescue_action_with_handler(exception)

Tries to rescue the exception by looking up and calling a registered handler.

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 186
186:       def rescue_action_with_handler(exception)
187:         if handler = handler_for_rescue(exception)
188:           if handler.arity != 0
189:             handler.call(exception)
190:           else
191:             handler.call
192:           end
193:           true # don't rely on the return value of the handler
194:         end
195:       end


Module: ActionController::Rescue::ClassMethods

Module
ActionController::Rescue::ClassMethods
In: actionpack/lib/action_controller/rescue.rb
Methods
  • rescue_from
Public Instance methods
rescue_from(*klasses, &block)

Rescue exceptions raised in controller actions.

rescue_from receives a series of exception classes or class names, and a trailing :with option with the name of a method or a Proc object to be called to handle them. Alternatively a block can be given.

Handlers that take one argument will be called with the exception, so that the exception can be inspected when dealing with it.

Handlers are inherited. They are searched from right to left, from bottom to top, and up the hierarchy. The handler of the first class for which exception.is_a?(klass) holds true is the one invoked, if any.

class ApplicationController < ActionController::Base

  rescue_from User::NotAuthorized, :with => :deny_access # self defined exception
  rescue_from ActiveRecord::RecordInvalid, :with => :show_errors

  rescue_from 'MyAppError::Base' do |exception|
    render :xml => exception, :status => 500
  end

  protected
    def deny_access
      ...
    end

    def show_errors(exception)
      exception.record.new_record? ? ...
    end

end

[ show source ]

     # File actionpack/lib/action_controller/rescue.rb, line 88
 88:       def rescue_from(*klasses, &block)
 89:         options = klasses.extract_options!
 90:         unless options.has_key?(:with)
 91:           block_given? ? options[:with] = block : raise(ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument.")
 92:         end
 93:
 94:         klasses.each do |klass|
 95:           key = if klass.is_a?(Class) && klass <= Exception
 96:             klass.name
 97:           elsif klass.is_a?(String)
 98:             klass
 99:           else
100:             raise(ArgumentError, "#{klass} is neither an Exception nor a String")
101:           end
102:
103:           # Order is important, we put the pair at the end. When dealing with an
104:           # exception we will follow the documented order going from right to left.
105:           rescue_handlers << [key, options[:with]]
106:         end
107:       end


Module: ActionController::Resources

Module
ActionController::Resources
In: actionpack/lib/action_controller/resources.rb

Overview

ActionController::Resources are a way of defining RESTful resources. A RESTful resource, in basic terms, is something that can be pointed at and it will respond with a representation of the data requested. In real terms this could mean a user with a browser requests an HTML page, or that a desktop application requests XML data.

RESTful design is based on the assumption that there are four generic verbs that a user of an application can request from a resource (the noun).

Resources can be requested using four basic HTTP verbs (GET, POST, PUT, DELETE), the method used denotes the type of action that should take place.

The Different Methods and their Usage

GET Requests for a resource, no saving or editing of a resource should occur in a GET request POST Creation of resources PUT Editing of attributes on a resource DELETE Deletion of a resource

Examples

  # A GET request on the Posts resource is asking for all Posts
  GET /posts

  # A GET request on a single Post resource is asking for that particular Post
  GET /posts/1

  # A POST request on the Posts resource is asking for a Post to be created with the supplied details
  POST /posts # with => { :post => { :title => "My Whizzy New Post", :body => "I've got a brand new combine harvester" } }

  # A PUT request on a single Post resource is asking for a Post to be updated
  PUT /posts # with => { :id => 1, :post => { :title => "Changed Whizzy Title" } }

  # A DELETE request on a single Post resource is asking for it to be deleted
  DELETE /posts # with => { :id => 1 }

By using the REST convention, users of our application can assume certain things about how the data is requested and how it is returned. Rails simplifies the routing part of RESTful design by supplying you with methods to create them in your routes.rb file.

Read more about REST at en.wikipedia.org/wiki/Representational_State_Transfer

Methods
  • resource
  • resources
Public Instance methods
resource(*entities, &block)

Creates named routes for implementing verb-oriented controllers for a singleton resource. A singleton resource is global to its current context. For unnested singleton resources, the resource is global to the current user visiting the application, such as a user‘s /account profile. For nested singleton resources, the resource is global to its parent resource, such as a projects resource that has_one :project_manager. The project_manager should be mapped as a singleton resource under projects:

  map.resources :projects do |project|
    project.resource :project_manager
  end

See map.resources for general conventions. These are the main differences:

  • A singular name is given to map.resource. The default controller name is still taken from the plural name.
  • To specify a custom plural name, use the :plural option. There is no :singular option.
  • No default index route is created for the singleton resource controller.
  • When nesting singleton resources, only the singular name is used as the path prefix (example: ‘account/messages/1’)

For example:

  map.resource :account

maps these actions in the Accounts controller:

  class AccountsController < ActionController::Base
    # GET new_account_url
    def new
      # return an HTML form for describing the new account
    end

    # POST account_url
    def create
      # create an account
    end

    # GET account_url
    def show
      # find and return the account
    end

    # GET edit_account_url
    def edit
      # return an HTML form for editing the account
    end

    # PUT account_url
    def update
      # find and update the account
    end

    # DELETE account_url
    def destroy
      # delete the account
    end
  end

Along with the routes themselves, resource generates named routes for use in controllers and views. map.resource :account produces these named routes and helpers:

  Named Route   Helpers
  ============  =============================================
  account       account_url, hash_for_account_url,
                account_path, hash_for_account_path

  new_account   new_account_url, hash_for_new_account_url,
                new_account_path, hash_for_new_account_path

  edit_account  edit_account_url, hash_for_edit_account_url,
                edit_account_path, hash_for_edit_account_path

[ show source ]

     # File actionpack/lib/action_controller/resources.rb, line 384
384:     def resource(*entities, &block)
385:       options = entities.extract_options!
386:       entities.each { |entity| map_singleton_resource(entity, options.dup, &block) }
387:     end
resources(*entities, &block)

Creates named routes for implementing verb-oriented controllers for a collection resource.

For example:

  map.resources :messages

will map the following actions in the corresponding controller:

  class MessagesController < ActionController::Base
    # GET messages_url
    def index
      # return all messages
    end

    # GET new_message_url
    def new
      # return an HTML form for describing a new message
    end

    # POST messages_url
    def create
      # create a new message
    end

    # GET message_url(:id => 1)
    def show
      # find and return a specific message
    end

    # GET edit_message_url(:id => 1)
    def edit
      # return an HTML form for editing a specific message
    end

    # PUT message_url(:id => 1)
    def update
      # find and update a specific message
    end

    # DELETE message_url(:id => 1)
    def destroy
      # delete a specific message
    end
  end

Along with the routes themselves, resources generates named routes for use in controllers and views. map.resources :messages produces the following named routes and helpers:

  Named Route   Helpers
  ============  =====================================================
  messages      messages_url, hash_for_messages_url,
                messages_path, hash_for_messages_path

  message       message_url(id), hash_for_message_url(id),
                message_path(id), hash_for_message_path(id)

  new_message   new_message_url, hash_for_new_message_url,
                new_message_path, hash_for_new_message_path

  edit_message  edit_message_url(id), hash_for_edit_message_url(id),
                edit_message_path(id), hash_for_edit_message_path(id)

You can use these helpers instead of url_for or methods that take url_for parameters. For example:

  redirect_to :controller => 'messages', :action => 'index'
  # and
  <%= link_to "edit this message", :controller => 'messages', :action => 'edit', :id => @message.id %>

now become:

  redirect_to messages_url
  # and
  <%= link_to "edit this message", edit_message_url(@message) # calls @message.id automatically

Since web browsers don‘t support the PUT and DELETE verbs, you will need to add a parameter ‘_method’ to your form tags. The form helpers make this a little easier. For an update form with a @message object:

  <%= form_tag message_path(@message), :method => :put %>

or

  <% form_for :message, @message, :url => message_path(@message), :html => {:method => :put} do |f| %>

The resources method accepts the following options to customize the resulting routes:

  • :collection - add named routes for other actions that operate on the collection. Takes a hash of #{action} => #{method}, where method is :get/:post/:put/:delete or :any if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url.
  • :member - same as :collection, but for actions that operate on a specific member.
  • :new - same as :collection, but for actions that operate on the new resource action.
  • :controller - specify the controller name for the routes.
  • :singular - specify the singular name used in the member routes.
  • :requirements - set custom routing parameter requirements.
  • :conditions - specify custom routing recognition conditions. Resources sets the :method value for the method-specific routes.
  • :path_prefix - set a prefix to the routes with required route variables.

    Weblog comments usually belong to a post, so you might use resources like:

      map.resources :articles
  map.resources :comments, :path_prefix => '/articles/:article_id'

    You can nest resources calls to set this automatically:

      map.resources :articles do |article|
    article.resources :comments
  end

    The comment resources work the same, but must now include a value for :article_id.

      article_comments_url(@article)
  article_comment_url(@article, @comment)

  article_comments_url(:article_id => @article)
  article_comment_url(:article_id => @article, :id => @comment)
  • :name_prefix - define a prefix for all generated routes, usually ending in an underscore. Use this if you have named routes that may clash.
      map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_'
  map.resources :tags, :path_prefix => '/toys/:toy_id',   :name_prefix => 'toy_'

You may also use :name_prefix to override the generic named routes in a nested resource:

  map.resources :articles do |article|
    article.resources :comments, :name_prefix => nil
  end

This will yield named resources like so:

  comments_url(@article)
  comment_url(@article, @comment)

If map.resources is called with multiple resources, they all get the same options applied.

Examples:

  map.resources :messages, :path_prefix => "/thread/:thread_id"
  # --> GET /thread/7/messages/1

  map.resources :messages, :collection => { :rss => :get }
  # --> GET /messages/rss (maps to the #rss action)
  #     also adds a named route called "rss_messages"

  map.resources :messages, :member => { :mark => :post }
  # --> POST /messages/1/mark (maps to the #mark action)
  #     also adds a named route called "mark_message"

  map.resources :messages, :new => { :preview => :post }
  # --> POST /messages/new/preview (maps to the #preview action)
  #     also adds a named route called "preview_new_message"

  map.resources :messages, :new => { :new => :any, :preview => :post }
  # --> POST /messages/new/preview (maps to the #preview action)
  #     also adds a named route called "preview_new_message"
  # --> /messages/new can be invoked via any request method

  map.resources :messages, :controller => "categories",
        :path_prefix => "/category/:category_id",
        :name_prefix => "category_"
  # --> GET /categories/7/messages/1
  #     has named route "category_message"

The resources method sets HTTP method restrictions on the routes it generates. For example, making an HTTP POST on new_message_url will raise a RoutingError exception. The default route in config/routes.rb overrides this and allows invalid HTTP methods for resource routes.

[ show source ]

     # File actionpack/lib/action_controller/resources.rb, line 310
310:     def resources(*entities, &block)
311:       options = entities.extract_options!
312:       entities.each { |entity| map_resource(entity, options.dup, &block) }
313:     end


Module: ActionController::Routing

Module
ActionController::Routing
In: actionpack/lib/action_controller/routing.rb actionpack/lib/action_controller/routing_optimisation.rb

Routing

The routing module provides URL rewriting in native Ruby. It‘s a way to redirect incoming requests to controllers and actions. This replaces mod_rewrite rules. Best of all, Rails’ Routing works with any web server. Routes are defined in routes.rb in your RAILS_ROOT/config directory.

Consider the following route, installed by Rails when you generate your application:

  map.connect ':controller/:action/:id'

This route states that it expects requests to consist of a :controller followed by an :action that in turn is fed some :id.

Suppose you get an incoming request for /blog/edit/22, you‘ll end up with:

  params = { :controller => 'blog',
             :action     => 'edit',
             :id         => '22'
          }

Think of creating routes as drawing a map for your requests. The map tells them where to go based on some predefined pattern:

 ActionController::Routing::Routes.draw do |map|
  Pattern 1 tells some request to go to one place
  Pattern 2 tell them to go to another
  ...
 end

The following symbols are special:

  :controller maps to your controller name
  :action     maps to an action with your controllers

Other names simply map to a parameter as in the case of +:id+.

Route priority

Not all routes are created equally. Routes have priority defined by the order of appearance of the routes in the routes.rb file. The priority goes from top to bottom. The last route in that file is at the lowest priority and will be applied last. If no route matches, 404 is returned.

Within blocks, the empty pattern is at the highest priority. In practice this works out nicely:

 ActionController::Routing::Routes.draw do |map|
   map.with_options :controller => 'blog' do |blog|
     blog.show '',  :action => 'list'
   end
   map.connect ':controller/:action/:view'
 end

In this case, invoking blog controller (with an URL like ’/blog/’) without parameters will activate the ‘list’ action by default.

Defaults routes and default parameters

Setting a default route is straightforward in Rails - you simply append a Hash at the end of your mapping to set any default parameters.

Example:

 ActionController::Routing:Routes.draw do |map|
   map.connect ':controller/:action/:id', :controller => 'blog'
 end

This sets up blog as the default controller if no other is specified. This means visiting ’/’ would invoke the blog controller.

More formally, you can define defaults in a route with the +:defaults+ key.

  map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' }

Named routes

Routes can be named with the syntax map.name_of_route options, allowing for easy reference within your source as name_of_route_url for the full URL and name_of_route_path for the URI path.

Example:

  # In routes.rb
  map.login 'login', :controller => 'accounts', :action => 'login'

  # With render, redirect_to, tests, etc.
  redirect_to login_url

Arguments can be passed as well.

  redirect_to show_item_path(:id => 25)

Use map.root as a shorthand to name a route for the root path "".

  # In routes.rb
  map.root :controller => 'blogs'

  # would recognize http://www.example.com/ as
  params = { :controller => 'blogs', :action => 'index' }

  # and provide these named routes
  root_url   # => 'http://www.example.com/'
  root_path  # => ''

Note: when using with_options, the route is simply named after the method you call on the block parameter rather than map.

  # In routes.rb
  map.with_options :controller => 'blog' do |blog|
    blog.show    '',            :action  => 'list'
    blog.delete  'delete/:id',  :action  => 'delete',
    blog.edit    'edit/:id',    :action  => 'edit'
  end

  # provides named routes for show, delete, and edit
  link_to @article.title, show_path(:id => @article.id)

Pretty URLs

Routes can generate pretty URLs. For example:

 map.connect 'articles/:year/:month/:day',
             :controller => 'articles',
             :action     => 'find_by_date',
             :year       => /\d{4}/,
             :month      => /\d{1,2}/,
             :day        => /\d{1,2}/

 # Using the route above, the url below maps to:
 # params = {:year => '2005', :month => '11', :day => '06'}
 # http://localhost:3000/articles/2005/11/06

Regular Expressions and parameters

You can specify a regular expression to define a format for a parameter.

 map.geocode 'geocode/:postalcode', :controller => 'geocode',
             :action => 'show', :postalcode => /\d{5}(-\d{4})?/

or, more formally:

  map.geocode 'geocode/:postalcode', :controller => 'geocode',
              :action => 'show', :requirements => { :postalcode => /\d{5}(-\d{4})?/ }

Route globbing

Specifying *[string] as part of a rule like:

 map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?'

will glob all remaining parts of the route that were not recognized earlier. This idiom must appear at the end of the path. The globbed values are in params[:path] in this case.

Route conditions

With conditions you can define restrictions on routes. Currently the only valid condition is :method.

  • :method - Allows you to specify which method can access the route. Possible values are :post, :get, :put, :delete and :any. The default value is :any, :any means that any method can access the route.

Example:

  map.connect 'post/:id', :controller => 'posts', :action => 'show',
              :conditions => { :method => :get }
  map.connect 'post/:id', :controller => 'posts', :action => 'create_comment',
              :conditions => { :method => :post }

Now, if you POST to /posts/:id, it will route to the create_comment action. A GET on the same URL will route to the show action.

Reloading routes

You can reload routes if you feel you must:

 ActionController::Routing::Routes.reload

This will clear all named routes and reload routes.rb if the file has been modified from last load. To absolutely force reloading, use +reload!+.

Testing Routes

The two main methods for testing your routes:

assert_routing

 def test_movie_route_properly_splits
  opts = {:controller => "plugin", :action => "checkout", :id => "2"}
  assert_routing "plugin/checkout/2", opts
 end

assert_routing lets you test whether or not the route properly resolves into options.

assert_recognizes

 def test_route_has_options
  opts = {:controller => "plugin", :action => "show", :id => "12"}
  assert_recognizes opts, "/plugins/show/12"
 end

Note the subtle difference between the two: assert_routing tests that a URL fits options while assert_recognizes tests that a URL breaks into parameters properly.

In tests you can simply pass the URL or named route to get or post.

 def send_to_jail
   get '/jail'
   assert_response :success
   assert_template "jail/front"
 end

 def goes_to_login
   get login_url
   #...
 end

View a list of all your routes

Run rake routes.

Methods
  • controller_relative_to
  • inflections_with_route_reloading
  • normalize_paths
  • possible_controllers
  • use_controllers!
  • with_controllers
Classes and Modules
Module ActionController::Routing::Helpers
Module ActionController::Routing::Optimisation
Module ActionController::Routing::RouteSet
Constants
SEPARATORS | = | %w( / . ? )
HTTP_METHODS | = | [:get, :head, :post, :put, :delete]
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION | = | [:controller, :action].to_set
Routes | = | RouteSet.new
Public Class methods
controller_relative_to(controller, previous)

[ show source ]

     # File actionpack/lib/action_controller/routing.rb, line 346
346:       def controller_relative_to(controller, previous)
347:         if controller.nil?           then previous
348:         elsif controller[0] == ?/    then controller[1..-1]
349:         elsif %r{^(.*)/} =~ previous then "#{$1}/#{controller}"
350:         else controller
351:         end
352:       end
normalize_paths(paths)

[ show source ]

     # File actionpack/lib/action_controller/routing.rb, line 300
300:       def normalize_paths(paths)
301:         # do the hokey-pokey of path normalization...
302:         paths = paths.collect do |path|
303:           path = path.
304:             gsub("//", "/").           # replace double / chars with a single
305:             gsub("\\\\", "\\").        # replace double \ chars with a single
306:             gsub(%r{(.)[\\/]$}, '\1')  # drop final / or \ if path ends with it
307:
308:           # eliminate .. paths where possible
309:           re = %r{\w+[/\\]\.\.[/\\]}
310:           path.gsub!(%r{\w+[/\\]\.\.[/\\]}, "") while path.match(re)
311:           path
312:         end
313:
314:         # start with longest path, first
315:         paths = paths.uniq.sort_by { |path| - path.length }
316:       end
possible_controllers()

[ show source ]

     # File actionpack/lib/action_controller/routing.rb, line 318
318:       def possible_controllers
319:         unless @possible_controllers
320:           @possible_controllers = []
321:
322:           paths = controller_paths.select { |path| File.directory?(path) && path != "." }
323:
324:           seen_paths = Hash.new {|h, k| h[k] = true; false}
325:           normalize_paths(paths).each do |load_path|
326:             Dir["#{load_path}/**/*_controller.rb"].collect do |path|
327:               next if seen_paths[path.gsub(%r{^\.[/\\]}, "")]
328:
329:               controller_name = path[(load_path.length + 1)..-1]
330:
331:               controller_name.gsub!(/_controller\.rb\Z/, '')
332:               @possible_controllers << controller_name
333:             end
334:           end
335:
336:           # remove duplicates
337:           @possible_controllers.uniq!
338:         end
339:         @possible_controllers
340:       end
use_controllers!(controller_names)

[ show source ]

     # File actionpack/lib/action_controller/routing.rb, line 342
342:       def use_controllers!(controller_names)
343:         @possible_controllers = controller_names
344:       end
with_controllers(names) {|| ...}

[ show source ]

     # File actionpack/lib/action_controller/routing.rb, line 292
292:       def with_controllers(names)
293:         prior_controllers = @possible_controllers
294:         use_controllers! names
295:         yield
296:       ensure
297:         use_controllers! prior_controllers
298:       end
Public Instance methods
inflections_with_route_reloading(&block)

[ show source ]

      # File actionpack/lib/action_controller/routing.rb, line 1492
1492:       def inflections_with_route_reloading(&block)
1493:         returning(inflections_without_route_reloading(&block)) {
1494:           ActionController::Routing::Routes.reload! if block_given?
1495:         }
1496:       end


Module: ActionController::Routing::Helpers

Module
ActionController::Routing::Helpers
In: actionpack/lib/action_controller/routing.rb

A helper module to hold URL related helpers.

Included Modules
  • PolymorphicRoutes


Module: ActionController::Routing::Optimisation

Module
ActionController::Routing::Optimisation
In: actionpack/lib/action_controller/routing_optimisation.rb

Much of the slow performance from routes comes from the complexity of expiry, :requirements matching, defaults providing and figuring out which url pattern to use. With named routes we can avoid the expense of finding the right route. So if they‘ve provided the right number of arguments, and have no :requirements, we can just build up a string and return it.

To support building optimisations for other common cases, the generation code is separated into several classes

Methods
  • generate_optimisation_block
Classes and Modules
Class ActionController::Routing::Optimisation::Optimiser
Class ActionController::Routing::Optimisation::PositionalArguments
Class ActionController::Routing::Optimisation::PositionalArgumentsWithAdditionalParams
Constants
OPTIMISERS = [PositionalArguments, PositionalArgumentsWithAdditionalParams]
Public Instance methods
generate_optimisation_block(route, kind)

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 13
13:       def generate_optimisation_block(route, kind)
14:         return "" unless route.optimise?
15:         OPTIMISERS.inject("") do |memo, klazz|
16:           memo << klazz.new(route, kind).source_code
17:           memo
18:         end
19:       end


Class: ActionController::Routing::Optimisation::Optimiser

Class
ActionController::Routing::Optimisation::Optimiser
In: | actionpack/lib/action_controller/routing_optimisation.rb
Parent: | Object
Methods
  • applicable?
  • generation_code
  • guard_condition
  • new
  • source_code
Attributes
[R] | kind
[R] | route
Public Class methods
new(route, kind)

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 23
23:         def initialize(route, kind)
24:           @route = route
25:           @kind  = kind
26:         end
Public Instance methods
applicable?()

Temporarily disabled :url optimisation pending proper solution to Issues around request.host etc.

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 46
46:         def applicable?
47:           true
48:         end
generation_code()

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 32
32:         def generation_code
33:           'nil'
34:         end
guard_condition()

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 28
28:         def guard_condition
29:           'false'
30:         end
source_code()

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 36
36:         def source_code
37:           if applicable?
38:             "return #{generation_code} if #{guard_condition}\n"
39:           else
40:             "\n"
41:           end
42:         end


Class: ActionController::Routing::Optimisation::PositionalArguments

Class
ActionController::Routing::Optimisation::PositionalArguments
In: | actionpack/lib/action_controller/routing_optimisation.rb
Parent: | Optimiser

Given a route: map.person ’/people/:id‘

If the user calls person_url(@person), we can simply return a string like "/people/#{@person.to_param}" rather than triggering the expensive logic in url_for

Methods
  • generation_code
  • guard_condition
Public Instance methods
generation_code()

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 69
69:         def generation_code
70:           elements = []
71:           idx = 0
72:
73:           if kind == :url
74:             elements << '#{request.protocol}'
75:             elements << '#{request.host_with_port}'
76:           end
77:
78:           elements << '#{request.relative_url_root if request.relative_url_root}'
79:
80:           # The last entry in route.segments appears to # *always* be a
81:           # 'divider segment' for '/' but we have assertions to ensure that
82:           # we don't include the trailing slashes, so skip them.
83:           (route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment|
84:             if segment.is_a?(DynamicSegment)
85:               elements << segment.interpolation_chunk("args[#{idx}].to_param")
86:               idx += 1
87:             else
88:               elements << segment.interpolation_chunk
89:             end
90:           end
91:           %("#{elements * ''}")
92:         end
guard_condition()

[ show source ]

    # File actionpack/lib/action_controller/routing_optimisation.rb, line 58
58:         def guard_condition
59:           number_of_arguments = route.segment_keys.size
60:           # if they're using foo_url(:id=>2) it's one
61:           # argument, but we don't want to generate /foos/id2
62:           if number_of_arguments == 1
63:             "defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
64:           else
65:             "defined?(request) && request && args.size == #{number_of_arguments}"
66:           end
67:         end


Class: ActionController::Routing::Optimisation::PositionalArgumentsWithAdditionalParams

Class
ActionController::Routing::Optimisation::PositionalArgumentsWithAdditionalParams
In: | actionpack/lib/action_controller/routing_optimisation.rb
Parent: | PositionalArguments

This case is mostly the same as the positional arguments case above, but it supports additional query parameters as the last argument

Methods
  • applicable?
  • generation_code
  • guard_condition
Public Instance methods
applicable?()

To avoid generating localhost/?host=foo.example.com we can‘t use this optimisation on routes without any segments

[ show source ]

     # File actionpack/lib/action_controller/routing_optimisation.rb, line 111
111:         def applicable?
112:           super && route.segment_keys.size > 0
113:         end
generation_code()

This case uses almost the same code as positional arguments, but add an args.last.to_query on the end

[ show source ]

     # File actionpack/lib/action_controller/routing_optimisation.rb, line 105
105:         def generation_code
106:           super.insert(-2, '?#{args.last.to_query}')
107:         end
guard_condition()

[ show source ]

     # File actionpack/lib/action_controller/routing_optimisation.rb, line 99
 99:         def guard_condition
100:           "defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
101:         end


Module: ActionController::Routing::RouteSet

Module
ActionController::Routing::RouteSet
In:
Classes and Modules
Class ActionController::Routing::RouteSet::Mapper


Class: ActionController::Routing::RouteSet::Mapper

Class
ActionController::Routing::RouteSet::Mapper
In: | actionpack/lib/action_controller/routing.rb
Parent: | Object

Mapper instances are used to build routes. The object passed to the draw block in config/routes.rb is a Mapper instance.

Mapper instances have relatively few instance methods, in order to avoid clashes with named routes.

Methods
  • connect
  • namespace
  • root
Public Instance methods
connect(path, options = {})

Create an unnamed route with the provided path and options. See ActionController::Routing for an introduction to routes.

[ show source ]

      # File actionpack/lib/action_controller/routing.rb, line 1064
1064:         def connect(path, options = {})
1065:           @set.add_route(path, options)
1066:         end
namespace(name, options = {}, &block)

Enables the use of resources in a module by setting the name_prefix, path_prefix, and namespace for the model. Example:

  map.namespace(:admin) do |admin|
    admin.resources :products,
      :has_many => [ :tags, :images, :variants ]
  end

This will create admin_products_url pointing to "admin/products", which will look for an Admin::ProductsController. It‘ll also create admin_product_tags_url pointing to "admin/products/#{product_id}/tags", which will look for Admin::TagsController.

[ show source ]

      # File actionpack/lib/action_controller/routing.rb, line 1088
1088:         def namespace(name, options = {}, &block)
1089:           if options[:namespace]
1090:             with_options({:path_prefix => "#{options.delete(:path_prefix)}/#{name}", :name_prefix => "#{options.delete(:name_prefix)}#{name}_", :namespace => "#{options.delete(:namespace)}#{name}/" }.merge(options), &block)
1091:           else
1092:             with_options({:path_prefix => name, :name_prefix => "#{name}_", :namespace => "#{name}/" }.merge(options), &block)
1093:           end
1094:         end
root(options = {})

Creates a named route called "root" for matching the root level request.

[ show source ]

      # File actionpack/lib/action_controller/routing.rb, line 1069
1069:         def root(options = {})
1070:           named_route("root", '', options)
1071:         end


Module: ActionController::SessionManagement::ClassMethods

Module
ActionController::SessionManagement::ClassMethods
In: actionpack/lib/action_controller/session_management.rb
Methods
  • session
  • session=
  • session_options
  • session_store
  • session_store=
Public Instance methods
session(*args)

Specify how sessions ought to be managed for a subset of the actions on the controller. Like filters, you can specify :only and :except clauses to restrict the subset, otherwise options apply to all actions on this controller.

The session options are inheritable, as well, so if you specify them in a parent controller, they apply to controllers that extend the parent.

Usage:

  # turn off session management for all actions.
  session :off

  # turn off session management for all actions _except_ foo and bar.
  session :off, :except => %w(foo bar)

  # turn off session management for only the foo and bar actions.
  session :off, :only => %w(foo bar)

  # the session will only work over HTTPS, but only for the foo action
  session :only => :foo, :session_secure => true

  # the session will only be disabled for 'foo', and only if it is
  # requested as a web service
  session :off, :only => :foo,
          :if => Proc.new { |req| req.parameters[:ws] }

  # the session will be disabled for non html/ajax requests
  session :off,
    :if => Proc.new { |req| !(req.format.html? || req.format.js?) }

All session options described for ActionController::Base.process_cgi are valid arguments.

This method is also aliased as session=

[ show source ]

    # File actionpack/lib/action_controller/session_management.rb, line 72
72:       def session(*args)
73:         options = args.extract_options!
74:
75:         options[:disabled] = true if !args.empty?
76:         options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only]
77:         options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except]
78:         if options[:only] && options[:except]
79:           raise ArgumentError, "only one of either :only or :except are allowed"
80:         end
81:
82:         write_inheritable_array("session_options", [options])
83:       end
session=(*args)

Alias for session

session_options()

Returns the hash used to configure the session. Example use:

  ActionController::Base.session_options[:session_secure] = true # session only available over HTTPS

[ show source ]

    # File actionpack/lib/action_controller/session_management.rb, line 35
35:       def session_options
36:         ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
37:       end
session_store()

Returns the session store class currently used.

[ show source ]

    # File actionpack/lib/action_controller/session_management.rb, line 28
28:       def session_store
29:         ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager]
30:       end
session_store=(store)

Set the session store to be used for keeping the session data between requests. By default, sessions are stored in browser cookies (:cookie_store), but you can also specify one of the other included stores (:active_record_store, :p_store, drb_store, :mem_cache_store, or :memory_store) or your own custom class.

[ show source ]

    # File actionpack/lib/action_controller/session_management.rb, line 22
22:       def session_store=(store)
23:         ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] =
24:           store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store
25:       end


Module: ActionController::Streaming

Module
ActionController::Streaming
In: actionpack/lib/action_controller/streaming.rb

Methods for sending files and streams to the browser instead of rendering.

Methods
  • send_data
  • send_file
Constants
DEFAULT_SEND_FILE_OPTIONS = { :type => 'application/octet-stream'.freeze, :disposition => 'attachment'.freeze, :stream => true, :buffer_size => 4096
Protected Instance methods
send_data(data, options = {})

Send binary data to the user as a file download. May set content type, apparent file name, and specify whether to show data inline or download as an attachment.

Options:

  • :filename - Suggests a filename for the browser to use.
  • :type - specifies an HTTP content type. Defaults to ‘application/octet-stream’.
  • :disposition - specifies whether the file will be shown inline or downloaded. Valid values are ‘inline’ and ‘attachment’ (default).
  • :status - specifies the status code to send with the response. Defaults to ‘200 OK’.

Generic data download:

  send_data buffer

Download a dynamically-generated tarball:

  send_data generate_tgz('dir'), :filename => 'dir.tgz'

Display an image Active Record in the browser:

  send_data image.data, :type => image.content_type, :disposition => 'inline'

See send_file for more information on HTTP Content-* headers and caching.

[ show source ]

     # File actionpack/lib/action_controller/streaming.rb, line 107
107:       def send_data(data, options = {}) #:doc:
108:         logger.info "Sending data #{options[:filename]}" unless logger.nil?
109:         send_file_headers! options.merge(:length => data.size)
110:         @performed_render = false
111:         render :status => options[:status], :text => data
112:       end
send_file(path, options = {})

Sends the file by streaming it 4096 bytes at a time. This way the whole file doesn‘t need to be read into memory at once. This makes 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 download any file on your server.

Options:

  • :filename - suggests a filename for the browser to use. Defaults to File.basename(path).
  • :type - specifies an HTTP content type. Defaults to ‘application/octet-stream’.
  • :disposition - specifies whether the file will be shown inline or downloaded. Valid values are ‘inline’ and ‘attachment’ (default).
  • :stream - whether to send the file to the user agent as it is read (true) or to read the entire file before sending (false). Defaults to true.
  • :buffer_size - specifies size (in bytes) of the buffer used to stream the file. Defaults to 4096.
  • :status - specifies the status code to send with the response. Defaults to ‘200 OK’.
  • :url_based_filename - set to true if you want the browser guess the filename from the URL, which is necessary for i18n filenames on certain browsers (setting :filename overrides this option).

The default Content-Type and Content-Disposition headers are set to download arbitrary binary files in as many browsers as possible. IE versions 4, 5, 5.5, and 6 are all known to have a variety of quirks (especially when downloading over SSL).

Simple download:

  send_file '/path/to.zip'

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). www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11

Also be aware that the document may be cached by proxies and browsers. The Pragma and Cache-Control headers declare how the file may be cached by intermediaries. They default to require clients to validate with the server before releasing cached responses. See www.mnot.net/cache_docs/ for an overview of web caching and www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 for the Cache-Control header spec.

[ show source ]

    # File actionpack/lib/action_controller/streaming.rb, line 61
61:       def send_file(path, options = {}) #:doc:
62:         raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
63:
64:         options[:length]   ||= File.size(path)
65:         options[:filename] ||= File.basename(path) unless options[:url_based_filename]
66:         send_file_headers! options
67:
68:         @performed_render = false
69:
70:         if options[:stream]
71:           render :status => options[:status], :text => Proc.new { |response, output|
72:             logger.info "Streaming file #{path}" unless logger.nil?
73:             len = options[:buffer_size] || 4096
74:             File.open(path, 'rb') do |file|
75:               while buf = file.read(len)
76:                 output.write(buf)
77:               end
78:             end
79:           }
80:         else
81:           logger.info "Sending file #{path}" unless logger.nil?
82:           File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read }
83:         end
84:       end


Class: ActionController::TestCase

Class
ActionController::TestCase
In: | actionpack/lib/action_controller/test_case.rb
Parent: | ActiveSupport::TestCase
Methods
  • controller_class
  • controller_class=
  • determine_default_controller_class
  • prepare_controller_class
  • rescue_action
  • setup
  • tests
Public Class methods
controller_class()

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 24
24:       def controller_class
25:         if current_controller_class = read_inheritable_attribute(:controller_class)
26:           current_controller_class
27:         else
28:           self.controller_class= determine_default_controller_class(name)
29:         end
30:       end
controller_class=(new_class)

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 19
19:       def controller_class=(new_class)
20:         prepare_controller_class(new_class)
21:         write_inheritable_attribute(:controller_class, new_class)
22:       end
determine_default_controller_class(name)

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 32
32:       def determine_default_controller_class(name)
33:         name.sub(/Test$/, '').constantize
34:       rescue NameError
35:         raise NonInferrableControllerError.new(name)
36:       end
prepare_controller_class(new_class)

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 38
38:       def prepare_controller_class(new_class)
39:         new_class.class_eval do
40:           def rescue_action(e)
41:             raise e
42:           end
43:         end
44:       end
rescue_action(e)

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 40
40:           def rescue_action(e)
41:             raise e
42:           end
tests(controller_class)

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 15
15:       def tests(controller_class)
16:         self.controller_class = controller_class
17:       end
Public Instance methods
setup()

[ show source ]

    # File actionpack/lib/action_controller/test_case.rb, line 47
47:     def setup
48:       @controller = self.class.controller_class.new
49:       @request    = TestRequest.new
50:       @response   = TestResponse.new
51:     end


Module: ActionController::TestProcess

Module
ActionController::TestProcess
In: actionpack/lib/action_controller/test_process.rb
Methods
  • assigns
  • build_request_uri
  • cookies
  • find_all_tag
  • find_tag
  • fixture_file_upload
  • flash
  • follow_redirect
  • html_document
  • included
  • method_missing
  • process
  • redirect_to_url
  • session
  • with_routing
  • xhr
  • xml_http_request
Public Class methods
included(base)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 359
359:     def self.included(base)
360:       # execute the request simulating a specific http method and set/volley the response
361:       %w( get post put delete head ).each do |method|
362:         base.class_eval "def \#{method}(action, parameters = nil, session = nil, flash = nil)\n@request.env['REQUEST_METHOD'] = \"\#{method.upcase}\" if defined?(@request)\nprocess(action, parameters, session, flash)\nend\n", __FILE__, __LINE__
363:       end
364:     end
Public Instance methods
assigns(key = nil)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 416
416:     def assigns(key = nil)
417:       if key.nil?
418:         @response.template.assigns
419:       else
420:         @response.template.assigns[key.to_s]
421:       end
422:     end
build_request_uri(action, parameters)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 440
440:     def build_request_uri(action, parameters)
441:       unless @request.env['REQUEST_URI']
442:         options = @controller.send!(:rewrite_options, parameters)
443:         options.update(:only_path => true, :action => action)
444:
445:         url = ActionController::UrlRewriter.new(@request, parameters)
446:         @request.set_REQUEST_URI(url.rewrite(options))
447:       end
448:     end
cookies()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 432
432:     def cookies
433:       @response.cookies
434:     end
find_all_tag(conditions)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 459
459:     def find_all_tag(conditions)
460:       html_document.find_all(conditions)
461:     end
find_tag(conditions)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 455
455:     def find_tag(conditions)
456:       html_document.find(conditions)
457:     end
fixture_file_upload(path, mime_type = nil, binary = false)

Shortcut for ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type). Example:

  post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')

To upload binary files on Windows, pass :binary as the last parameter. This will not affect other platforms.

  post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 473
473:     def fixture_file_upload(path, mime_type = nil, binary = false)
474:       ActionController::TestUploadedFile.new(
475:         Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path,
476:         mime_type,
477:         binary
478:       )
479:     end
flash()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 428
428:     def flash
429:       @response.flash
430:     end
follow_redirect()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 407
407:     def follow_redirect
408:       redirected_controller = @response.redirected_to[:controller]
409:       if redirected_controller && redirected_controller != @controller.controller_name
410:         raise "Can't follow redirects outside of current controller (from #{@controller.controller_name} to #{redirected_controller})"
411:       end
412:
413:       get(@response.redirected_to.delete(:action), @response.redirected_to.stringify_keys)
414:     end
html_document()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 450
450:     def html_document
451:       xml = @response.content_type =~ /xml$/
452:       @html_document ||= HTML::Document.new(@response.body, false, xml)
453:     end
method_missing(selector, *args)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 463
463:     def method_missing(selector, *args)
464:       return @controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
465:       return super
466:     end
process(action, parameters = nil, session = nil, flash = nil)

execute the request and set/volley the response

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 373
373:     def process(action, parameters = nil, session = nil, flash = nil)
374:       # Sanity check for required instance variables so we can give an
375:       # understandable error message.
376:       %w(@controller @request @response).each do |iv_name|
377:         if !(instance_variables.include?(iv_name) || instance_variables.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
378:           raise "#{iv_name} is nil: make sure you set it in your test's setup method."
379:         end
380:       end
381:
382:       @request.recycle!
383:
384:       @html_document = nil
385:       @request.env['REQUEST_METHOD'] ||= "GET"
386:       @request.action = action.to_s
387:
388:       parameters ||= {}
389:       @request.assign_parameters(@controller.class.controller_path, action.to_s, parameters)
390:
391:       @request.session = ActionController::TestSession.new(session) unless session.nil?
392:       @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
393:       build_request_uri(action, parameters)
394:       @controller.process(@request, @response)
395:     end
redirect_to_url()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 436
436:     def redirect_to_url
437:       @response.redirect_url
438:     end
session()

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 424
424:     def session
425:       @response.session
426:     end
with_routing() {|temporary_routes| ...}

A helper to make it easier to test different route configurations. This method temporarily replaces ActionController::Routing::Routes with a new RouteSet instance.

The new instance is yielded to the passed block. Typically the block will create some routes using map.draw { map.connect … }:

 with_routing do |set|
   set.draw do |map|
     map.connect ':controller/:action/:id'
       assert_equal(
         ['/content/10/show', {}],
         map.generate(:controller => 'content', :id => 10, :action => 'show')
     end
   end
 end

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 498
498:     def with_routing
499:       real_routes = ActionController::Routing::Routes
500:       ActionController::Routing.module_eval { remove_const :Routes }
501:
502:       temporary_routes = ActionController::Routing::RouteSet.new
503:       ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
504:
505:       yield temporary_routes
506:     ensure
507:       if ActionController::Routing.const_defined? :Routes
508:         ActionController::Routing.module_eval { remove_const :Routes }
509:       end
510:       ActionController::Routing.const_set(:Routes, real_routes) if real_routes
511:     end
xhr(request_method, action, parameters = nil, session = nil, flash = nil)

Alias for xml_http_request

xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
This method is also aliased as xhr

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 397
397:     def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
398:       @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
399:       @request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*'
400:       returning send!(request_method, action, parameters, session, flash) do
401:         @request.env.delete 'HTTP_X_REQUESTED_WITH'
402:         @request.env.delete 'HTTP_ACCEPT'
403:       end
404:     end


Class: ActionController::TestUploadedFile

Class
ActionController::TestUploadedFile
In: | actionpack/lib/action_controller/test_process.rb
Parent: | Object
Methods
  • new
Attributes
[R] | content_type | The content type of the "uploaded" file
[R] | original_filename | The filename, not including the path, of the "uploaded" file
Public Class methods
new(path, content_type = Mime::TEXT, binary = false)

[ show source ]

     # File actionpack/lib/action_controller/test_process.rb, line 338
338:     def initialize(path, content_type = Mime::TEXT, binary = false)
339:       raise "#{path} file does not exist" unless File.exist?(path)
340:       @content_type = content_type
341:       @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 }
342:       @tempfile = Tempfile.new(@original_filename)
343:       @tempfile.binmode if binary
344:       FileUtils.copy_file(path, @tempfile.path)
345:     end


Module: ActionController::UploadedFile

Module
ActionController::UploadedFile
In: actionpack/lib/action_controller/request.rb
Methods
  • included
  • original_filename
Public Class methods
included(base)

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 696
696:     def self.included(base)
697:       base.class_eval do
698:         attr_accessor :original_path, :content_type
699:         alias_method :local_path, :path
700:       end
701:     end
Public Instance methods
original_filename()

Take the basename of the upload‘s original filename. This handles the full Windows paths given by Internet Explorer (and perhaps other broken user agents) without affecting those which give the lone filename. The Windows regexp is adapted from Perl‘s File::Basename.

[ show source ]

     # File actionpack/lib/action_controller/request.rb, line 708
708:     def original_filename
709:       unless defined? @original_filename
710:         @original_filename =
711:           unless original_path.blank?
712:             if original_path =~ /^(?:.*[:\\\/])?(.*)/m
713:               $1
714:             else
715:               File.basename original_path
716:             end
717:           end
718:       end
719:       @original_filename
720:     end


Class: ActionController::UploadedStringIO

Class
ActionController::UploadedStringIO
In: | actionpack/lib/action_controller/request.rb
Parent: | StringIO
Included Modules
  • UploadedFile


Class: ActionController::UploadedTempfile

Class
ActionController::UploadedTempfile
In: | actionpack/lib/action_controller/request.rb
Parent: | Tempfile
Included Modules
  • UploadedFile


Module: ActionController::UrlWriter

Module
ActionController::UrlWriter
In: actionpack/lib/action_controller/url_rewriter.rb

Write URLs from arbitrary places in your codebase, such as your mailers.

Example:

  class MyMailer
    include ActionController::UrlWriter
    default_url_options[:host] = 'www.basecamphq.com'

    def signup_url(token)
      url_for(:controller => 'signup', action => 'index', :token => token)
    end
 end

In addition to providing url_for, named routes are also accessible after including UrlWriter.

Methods
  • url_for
Public Instance methods
url_for(options)

Generate a url based on the options provided, default_url_options and the routes defined in routes.rb. The following options are supported:

  • :only_path If true, the relative url is returned. Defaults to false.
  • :protocol The protocol to connect to. Defaults to ‘http’.
  • :host Specifies the host the link should be targetted at. If :only_path is false, this option must be provided either explicitly, or via default_url_options.
  • :port Optionally specify the port to connect to.
  • :anchor An anchor name to be appended to the path.

Any other key(:controller, :action, etc…) given to url_for is forwarded to the Routes module.

Examples:

   url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080'    # => 'http://somehost.org:8080/tasks/testing'
   url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true    # => '/tasks/testing#ok'
   url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33'  # => 'http://somehost.org/tasks/testing?number=33'

[ show source ]

    # File actionpack/lib/action_controller/url_rewriter.rb, line 47
47:     def url_for(options)
48:       options = self.class.default_url_options.merge(options)
49:
50:       url = ''
51:
52:       unless options.delete :only_path
53:         url << (options.delete(:protocol) || 'http')
54:         url << '://' unless url.match("://") #dont add separator if its already been specified in :protocol
55:
56:         raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
57:
58:         url << options.delete(:host)
59:         url << ":#{options.delete(:port)}" if options.key?(:port)
60:       else
61:         # Delete the unused options to prevent their appearance in the query string
62:         [:protocol, :host, :port].each { |k| options.delete k }
63:       end
64:
65:       anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options.key?(:anchor)
66:       url << Routing::Routes.generate(options, {})
67:       url << anchor if anchor
68:
69:       return url
70:     end


Module: ActionController::Verification::ClassMethods

Module
ActionController::Verification::ClassMethods
In: actionpack/lib/action_controller/verification.rb

This module provides a class-level method for specifying that certain actions are guarded against being called without certain prerequisites being met. This is essentially a special kind of before_filter.

An action may be guarded against being invoked without certain request parameters being set, or without certain session values existing.

When a verification is violated, values may be inserted into the flash, and a specified redirection is triggered. If no specific action is configured, verification failures will by default result in a 400 Bad Request response.

Usage:

  class GlobalController < ActionController::Base
    # Prevent the #update_settings action from being invoked unless
    # the 'admin_privileges' request parameter exists. The
    # settings action will be redirected to in current controller
    # if verification fails.
    verify :params => "admin_privileges", :only => :update_post,
           :redirect_to => { :action => "settings" }

    # Disallow a post from being updated if there was no information
    # submitted with the post, and if there is no active post in the
    # session, and if there is no "note" key in the flash. The route
    # named category_url will be redirected to if verification fails.

    verify :params => "post", :session => "post", "flash" => "note",
           :only => :update_post,
           :add_flash => { "alert" => "Failed to create your message" },
           :redirect_to => :category_url

Note that these prerequisites are not business rules. They do not examine the content of the session or the parameters. That level of validation should be encapsulated by your domain model or helper methods in the controller.

Methods
  • verify
Public Instance methods
verify(options={})

Verify the given actions so that if certain prerequisites are not met, the user is redirected to a different action. The options parameter is a hash consisting of the following key/value pairs:

  • :params - a single key or an array of keys that must be in the params hash in order for the action(s) to be safely called.
  • :session - a single key or an array of keys that must be in the session in order for the action(s) to be safely called.
  • :flash - a single key or an array of keys that must be in the flash in order for the action(s) to be safely called.
  • :method - a single key or an array of keys—any one of which must match the current request method in order for the action(s) to be safely called. (The key should be a symbol: :get or :post, for example.)
  • :xhr - true/false option to ensure that the request is coming from an Ajax call or not.
  • :add_flash - a hash of name/value pairs that should be merged into the session‘s flash if the prerequisites cannot be satisfied.
  • :add_headers - a hash of name/value pairs that should be merged into the response‘s headers hash if the prerequisites cannot be satisfied.
  • :redirect_to - the redirection parameters to be used when redirecting if the prerequisites cannot be satisfied. You can redirect either to named route or to the action in some controller.
  • :render - the render parameters to be used when the prerequisites cannot be satisfied.
  • :only - only apply this verification to the actions specified in the associated array (may also be a single value).
  • :except - do not apply this verification to the actions specified in the associated array (may also be a single value).

[ show source ]

    # File actionpack/lib/action_controller/verification.rb, line 73
73:       def verify(options={})
74:         filter_opts = { :only => options[:only], :except => options[:except] }
75:         before_filter(filter_opts) do |c|
76:           c.send! :verify_action, options
77:         end
78:       end


File: assertions.rb

File
assertions.rb
Path: | actionpack/lib/action_controller/assertions.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • test/unit/assertions


File: dom_assertions.rb

File
dom_assertions.rb
Path: | actionpack/lib/action_controller/assertions/dom_assertions.rb
Modified: | Sun Mar 02 11:08:57 -0700 2008


File: model_assertions.rb

File
model_assertions.rb
Path: | actionpack/lib/action_controller/assertions/model_assertions.rb
Modified: | Sun Mar 02 11:08:57 -0700 2008


File: response_assertions.rb

File
response_assertions.rb
Path: | actionpack/lib/action_controller/assertions/response_assertions.rb
Modified: | Sun Mar 02 11:08:57 -0700 2008

Required Files
  • rexml/document
  • html/document


File: routing_assertions.rb

File
routing_assertions.rb
Path: | actionpack/lib/action_controller/assertions/routing_assertions.rb
Modified: | Sun Mar 02 11:08:57 -0700 2008


File: selector_assertions.rb

File
selector_assertions.rb
Path: | actionpack/lib/action_controller/assertions/selector_assertions.rb
Modified: | Sun Mar 02 11:08:57 -0700 2008

Required Files
  • rexml/document
  • html/document


File: tag_assertions.rb

File
tag_assertions.rb
Path: | actionpack/lib/action_controller/assertions/tag_assertions.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • rexml/document
  • html/document


File: base.rb

File
base.rb
Path: | actionpack/lib/action_controller/base.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/mime_type
  • action_controller/request
  • action_controller/response
  • action_controller/routing
  • action_controller/resources
  • action_controller/url_rewriter
  • action_controller/status_codes
  • drb
  • set


File: benchmarking.rb

File
benchmarking.rb
Path: | actionpack/lib/action_controller/benchmarking.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • benchmark


File: caching.rb

File
caching.rb
Path: | actionpack/lib/action_controller/caching.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • fileutils
  • uri
  • set


File: cgi_ext.rb

File
cgi_ext.rb
Path: | actionpack/lib/action_controller/cgi_ext.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/cgi_ext/stdinput
  • action_controller/cgi_ext/query_extension
  • action_controller/cgi_ext/cookie
  • action_controller/cgi_ext/session


File: cookie.rb

File
cookie.rb
Path: | actionpack/lib/action_controller/cgi_ext/cookie.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: query_extension.rb

File
query_extension.rb
Path: | actionpack/lib/action_controller/cgi_ext/query_extension.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi


File: session.rb

File
session.rb
Path: | actionpack/lib/action_controller/cgi_ext/session.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • digest/md5
  • cgi/session
  • cgi/session/pstore
  • securerandom


File: stdinput.rb

File
stdinput.rb
Path: | actionpack/lib/action_controller/cgi_ext/stdinput.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi


File: cgi_process.rb

File
cgi_process.rb
Path: | actionpack/lib/action_controller/cgi_process.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/cgi_ext
  • action_controller/session/cookie_store


File: components.rb

File
components.rb
Path: | actionpack/lib/action_controller/components.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: cookies.rb

File
cookies.rb
Path: | actionpack/lib/action_controller/cookies.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: dispatcher.rb

File
dispatcher.rb
Path: | actionpack/lib/action_controller/dispatcher.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: filters.rb

File
filters.rb
Path: | actionpack/lib/action_controller/filters.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: flash.rb

File
flash.rb
Path: | actionpack/lib/action_controller/flash.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: helpers.rb

File
helpers.rb
Path: | actionpack/lib/action_controller/helpers.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

FIXME: helper { … } is broken on Ruby 1.9


File: http_authentication.rb

File
http_authentication.rb
Path: | actionpack/lib/action_controller/http_authentication.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • base64


File: integration.rb

File
integration.rb
Path: | actionpack/lib/action_controller/integration.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • dispatcher
  • stringio
  • uri
  • action_controller/test_process


File: layout.rb

File
layout.rb
Path: | actionpack/lib/action_controller/layout.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: mime_responds.rb

File
mime_responds.rb
Path: | actionpack/lib/action_controller/mime_responds.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: mime_type.rb

File
mime_type.rb
Path: | actionpack/lib/action_controller/mime_type.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/mime_types


File: mime_types.rb

File
mime_types.rb
Path: | actionpack/lib/action_controller/mime_types.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Build list of Mime types for HTTP responses www.iana.org/assignments/media-types/


File: polymorphic_routes.rb

File
polymorphic_routes.rb
Path: | actionpack/lib/action_controller/polymorphic_routes.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: record_identifier.rb

File
record_identifier.rb
Path: | actionpack/lib/action_controller/record_identifier.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: request.rb

File
request.rb
Path: | actionpack/lib/action_controller/request.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • tempfile
  • stringio
  • strscan


File: request_forgery_protection.rb

File
request_forgery_protection.rb
Path: | actionpack/lib/action_controller/request_forgery_protection.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: request_profiler.rb

File
request_profiler.rb
Path: | actionpack/lib/action_controller/request_profiler.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • optparse
  • action_controller/integration
  • ruby-prof


File: rescue.rb

File
rescue.rb
Path: | actionpack/lib/action_controller/rescue.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: resources.rb

File
resources.rb
Path: | actionpack/lib/action_controller/resources.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: response.rb

File
response.rb
Path: | actionpack/lib/action_controller/response.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • digest/md5


File: routing.rb

File
routing.rb
Path: | actionpack/lib/action_controller/routing.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • uri
  • action_controller/polymorphic_routes
  • action_controller/routing_optimisation


File: routing_optimisation.rb

File
routing_optimisation.rb
Path: | actionpack/lib/action_controller/routing_optimisation.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: active_record_store.rb

File
active_record_store.rb
Path: | actionpack/lib/action_controller/session/active_record_store.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • cgi/session
  • digest/md5
  • base64


File: cookie_store.rb

File
cookie_store.rb
Path: | actionpack/lib/action_controller/session/cookie_store.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • cgi/session
  • base64
  • openssl


File: drb_server.rb

File
drb_server.rb
Path: | actionpack/lib/action_controller/session/drb_server.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

This is a really simple session storage daemon, basically just a hash, which is enabled for DRb access.

Required Files
  • drb


File: drb_store.rb

File
drb_store.rb
Path: | actionpack/lib/action_controller/session/drb_store.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • cgi/session
  • drb


File: mem_cache_store.rb

File
mem_cache_store.rb
Path: | actionpack/lib/action_controller/session/mem_cache_store.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

cgi/session/memcached.rb - persistent storage of marshalled session data

Overview

This file provides the CGI::Session::MemCache class, which builds persistence of storage data on top of the MemCache library. See cgi/session.rb for more details on session storage managers.

Required Files
  • cgi/session


File: session_management.rb

File
session_management.rb
Path: | actionpack/lib/action_controller/session_management.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/session/cookie_store
  • action_controller/session/drb_store
  • action_controller/session/mem_cache_store
  • action_controller/session/active_record_store


File: status_codes.rb

File
status_codes.rb
Path: | actionpack/lib/action_controller/status_codes.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: streaming.rb

File
streaming.rb
Path: | actionpack/lib/action_controller/streaming.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: test_case.rb

File
test_case.rb
Path: | actionpack/lib/action_controller/test_case.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • active_support/test_case


File: test_process.rb

File
test_process.rb
Path: | actionpack/lib/action_controller/test_process.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_controller/assertions
  • stringio
  • tempfile


File: url_rewriter.rb

File
url_rewriter.rb
Path: | actionpack/lib/action_controller/url_rewriter.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: document.rb

File
document.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • html/tokenizer
  • html/node
  • html/selector
  • html/sanitizer


File: node.rb

File
node.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • strscan


File: sanitizer.rb

File
sanitizer.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: selector.rb

File
selector.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: tokenizer.rb

File
tokenizer.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • strscan


File: version.rb

File
version.rb
Path: | actionpack/lib/action_controller/vendor/html-scanner/html/version.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: verification.rb

File
verification.rb
Path: | actionpack/lib/action_controller/verification.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


Class: ActionView::Base

Class
ActionView::Base
In: | actionpack/lib/action_view/base.rb actionpack/lib/action_view/helpers/active_record_helper.rb actionpack/lib/action_view/helpers/form_helper.rb
Parent: | Object

Action View templates can be written in three ways. If the template file has a +.erb+ (or +.rhtml+) extension then it uses a mixture of ERb (included in Ruby) and HTML. If the template file has a +.builder+ (or +.rxml+) extension then Jim Weirich‘s Builder::XmlMarkup library is used. If the template file has a +.rjs+ extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.

ERb

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>
  <% for person in @people %>
    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 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

<%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>.

Using sub templates

Using sub templates allows you to sidestep tedious replication and extract common display structures in shared templates. The classic example is the use of a header and footer (even though the Action Pack-way would be to use Layouts):

  <%= render "shared/header" %>
  Something really specific and terrific
  <%= render "shared/footer" %>

As you see, we use the output embeddings for the render methods. The render call itself will just return a string holding the result of the rendering. The output embedding writes it to the current template.

But you don‘t have to restrict yourself to static includes. Templates can share variables amongst themselves by using instance variables defined using the regular embedding tags. Like this:

  <% @page_title = "A Wonderful Hello" %>
  <%= render "shared/header" %>

Now the header can pick up on the @page_title variable and use it for outputting a title tag:

  <title><%= @page_title %></title>

Passing local variables to sub templates

You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:

  <%= render "shared/header", { :headline => "Welcome", :person => person } %>

These can now be accessed in shared/header with:

  Headline: <%= headline %>
  First name: <%= person.first_name %>

If you need to find out whether a certain local variable has been assigned a value in a particular render call, you need to use the following pattern:

  <% if local_assigns.has_key? :headline %>
    Headline: <%= headline %>
  <% end %>

Testing using defined? headline will not work. This is an implementation restriction.

Template caching

By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will check the file‘s modification time and recompile it.

Builder

Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object named xml is automatically made available to templates with a +.builder+ extension.

Here are some basic examples:

  xml.em("emphasized")                              # => <em>emphasized</em>
  xml.em { xml.b("emph & bold") }                    # => <em><b>emph &amp; bold</b></em>
  xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
  xml.target("name"=>"compile", "option"=>"fast")   # => <target option="fast" name="compile"\>
                                                    # NOTE: order of attributes is not specified.

Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:

  xml.div {
    xml.h1(@person.name)
    xml.p(@person.bio)
  }

would produce something like:

  <div>
    <h1>David Heinemeier Hansson</h1>
    <p>A product of Danish Design during the Winter of '79...</p>
  </div>

A full-length RSS example actually used on Basecamp:

  xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
    xml.channel do
      xml.title(@feed_title)
      xml.link(@url)
      xml.description "Basecamp: Recent items"
      xml.language "en-us"
      xml.ttl "40"

      for item in @recent_items
        xml.item do
          xml.title(item_title(item))
          xml.description(item_description(item)) if item_description(item)
          xml.pubDate(item_pubDate(item))
          xml.guid(@person.firm.account.url + @recent_items.url(item))
          xml.link(@person.firm.account.url + @recent_items.url(item))

          xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
        end
      end
    end
  end

More builder documentation can be found at builder.rubyforge.org.

JavaScriptGenerator

JavaScriptGenerator templates end in +.rjs+. Unlike conventional templates which are used to render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax and make updates to the page where the request originated from.

An instance of the JavaScriptGenerator object named page is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.

When an .rjs action is called with link_to_remote, the generated JavaScript is automatically evaluated. Example:

  link_to_remote :url => {:action => 'delete'}

The subsequently rendered +delete.rjs+ might look like:

  page.replace_html  'sidebar', :partial => 'sidebar'
  page.remove        "person-#{@person.id}"
  page.visual_effect :highlight, 'user-list'

This refreshes the sidebar, removes a person element and highlights the user list.

See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.

Methods
  • append_view_path
  • full_template_path
  • handler_for_extension
  • prepend_view_path
  • register_default_template_handler
  • register_template_handler
  • template_format
  • template_handler_extensions
Included Modules
  • ERB::Util
  • CompiledTemplates
  • Helpers
Attributes
[RW] | assigns
[RW] | base_path
[RW] | controller
[R] | first_render
[R] | headers
[R] | logger
[R] | response
[RW] | template_extension
[W] | template_format
[RW] | view_paths
Public Class methods
handler_for_extension(extension)

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 255
255:     def self.handler_for_extension(extension)
256:       (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
257:     end
register_default_template_handler(extension, klass)

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 250
250:     def self.register_default_template_handler(extension, klass)
251:       register_template_handler(extension, klass)
252:       @@default_template_handlers = klass
253:     end
register_template_handler(extension, klass)

Register a class that knows how to handle template files with the given extension. This can be used to implement new template types. The constructor for the class must take the ActiveView::Base instance as a parameter, and the class must implement a render method that takes the contents of the template to render as well as the Hash of local assigns available to the template. The render method ought to return the rendered template as a string.

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 242
242:     def self.register_template_handler(extension, klass)
243:       @@template_handlers[extension.to_sym] = klass
244:     end
template_handler_extensions()

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 246
246:     def self.template_handler_extensions
247:       @@template_handler_extensions ||= @@template_handlers.keys.map(&:to_s).sort
248:     end
Public Instance methods
append_view_path(path)

Adds a view_path to the end of the view_paths array. This change affects the current request only.

  @template.append_view_path("views/default")
  @template.append_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 440
440:     def append_view_path(path)
441:       @view_paths.push(*path)
442:     end
full_template_path(template_path, extension)

Gets the full template path with base path for the given template_path and extension.

  full_template_path('users/show', 'html.erb')
  # => '~/rails/app/views/users/show.html.erb

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 378
378:     def full_template_path(template_path, extension)
379:       if @@cache_template_extensions
380:         (@@cached_base_paths[template_path] ||= {})[extension.to_s] ||= find_full_template_path(template_path, extension)
381:       else
382:         find_full_template_path(template_path, extension)
383:       end
384:     end
prepend_view_path(path)

Adds a view_path to the front of the view_paths array. This change affects the current request only.

  @template.prepend_view_path("views/default")
  @template.prepend_view_path(["views/default", "views/custom"])

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 430
430:     def prepend_view_path(path)
431:       @view_paths.unshift(*path)
432:     end
template_format()

symbolized version of the :format parameter of the request, or :html by default.

[ show source ]

     # File actionpack/lib/action_view/base.rb, line 418
418:     def template_format
419:       return @template_format if @template_format
420:       format = controller && controller.respond_to?(:request) && controller.request.parameters[:format]
421:       @template_format = format.blank? ? :html : format.to_sym
422:     end


Class: ActionView::CompiledTemplates

Class
ActionView::CompiledTemplates
In: | actionpack/lib/action_view/compiled_templates.rb
Parent: | Module

CompiledTemplates modules hold methods that have been compiled. Templates are compiled into these methods so that they do not need to be read and parsed for each request.

Each template may be compiled into one or more methods. Each method accepts a given set of parameters which is used to implement local assigns passing.

To use a compiled template module, create a new instance and include it into the class in which you want the template to be rendered.

Methods
  • compile_source
  • compiled?
  • full_key
  • mtime
  • new
  • selector
  • wrap_source
Attributes
[R] method_names
Public Class methods
new()

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 15
15:     def initialize
16:       @method_names = Hash.new do |hash, key|
17:         hash[key] = "__compiled_method_#{(hash.length + 1)}"
18:       end
19:       @mtimes = {}
20:     end
Public Instance methods
compile_source(identifier, arg_names, source, initial_line_number = 0, file_name = nil)

Compile the provided source code for the given argument names and with the given initial line number. The identifier should be unique to this source.

The file_name, if provided will appear in backtraces. If not provided, the file_name defaults to the identifier.

This method will return the selector for the compiled version of this method.

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 46
46:     def compile_source(identifier, arg_names, source, initial_line_number = 0, file_name = nil)
47:       file_name ||= identifier
48:       name = method_names[full_key(identifier, arg_names)]
49:       arg_desc = arg_names.empty? ? '' : "(#{arg_names * ', '})"
50:       fake_file_name = "#{file_name}#{arg_desc}" # Include the arguments for this version (for now)
51:
52:       method_def = wrap_source(name, arg_names, source)
53:
54:       begin
55:         module_eval(method_def, fake_file_name, initial_line_number)
56:         @mtimes[full_key(identifier, arg_names)] = Time.now
57:       rescue Exception => e  # errors from compiled source
58:         e.blame_file! identifier
59:         raise
60:       end
61:       name
62:     end
compiled?(identifier, arg_names)

Alias for selector

full_key(identifier, arg_names)

Return the full key for the given identifier and argument names

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 23
23:     def full_key(identifier, arg_names)
24:       [identifier, arg_names]
25:     end
mtime(identifier, arg_names)

Return the time at which the method for the given identifier and argument names was compiled.

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 35
35:     def mtime(identifier, arg_names)
36:       @mtimes[full_key(identifier, arg_names)]
37:     end
selector(identifier, arg_names)

Return the selector for this method or nil if it has not been compiled

This method is also aliased as compiled?

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 28
28:     def selector(identifier, arg_names)
29:       key = full_key(identifier, arg_names)
30:       method_names.key?(key) ? method_names[key] : nil
31:     end
wrap_source(name, arg_names, source)

Wrap the provided source in a def … end block.

[ show source ]

    # File actionpack/lib/action_view/compiled_templates.rb, line 65
65:     def wrap_source(name, arg_names, source)
66:       "def #{name}(#{arg_names * ', '})\n#{source}\nend"
67:     end


Module: ActionView::Helpers::ActiveRecordHelper

Module
ActionView::Helpers::ActiveRecordHelper
In: actionpack/lib/action_view/helpers/active_record_helper.rb

The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the form method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. In that case, it‘s better to use the input method and the specialized form methods in classes/ActionView/Helpers/FormHelper.html

Methods
  • error_message_on
  • error_messages_for
  • form
  • input
Public Instance methods
error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")

Returns a string containing the error message attached to the method on the object if one exists. This error message is wrapped in a DIV tag, which can be extended to include a prepend_text and/or append_text (to properly explain the error), and a css_class to style it accordingly. object should either be the name of an instance variable or the actual object. As an example, let‘s say you have a model post that has an error message on the title attribute:

  <%= error_message_on "post", "title" %> =>
    <div class="formError">can't be empty</div>

  <%= error_message_on @post, "title" %> =>
    <div class="formError">can't be empty</div>

  <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> =>
    <div class="inputError">Title simply can't be empty (or it won't work).</div>

[ show source ]

    # File actionpack/lib/action_view/helpers/active_record_helper.rb, line 91
91:       def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")
92:         if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
93:           (errors = obj.errors.on(method))
94:           content_tag("div", "#{prepend_text}#{errors.is_a?(Array) ? errors.first : errors}#{append_text}", :class => css_class)
95:         else
96:           ''
97:         end
98:       end
error_messages_for(*params)

Returns a string with a DIV containing all of the error messages for the objects located as instance variables by the names given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are provided.

This DIV can be tailored by the following options:

  • header_tag - Used for the header of the error div (default: h2)
  • id - The id of the error div (default: errorExplanation)
  • class - The class of the error div (default: errorExplanation)
  • object - The object (or array of objects) for which to display errors, if you need to escape the instance variable convention
  • object_name - The object name to use in the header, or any text that you prefer. If object_name is not set, the name of the first object will be used.
  • header_message - The message in the header of the error div. Pass nil or an empty string to avoid the header message altogether. (default: X errors prohibited this object from being saved)
  • message - The explanation message after the header message and before the error list. Pass nil or an empty string to avoid the explanation message altogether. (default: There were problems with the following fields:)

To specify the display for one object, you simply provide its name as a parameter. For example, for the User model:

  error_messages_for 'user'

To specify more than one object, you simply list them; optionally, you can add an extra object_name parameter, which will be the name used in the header message.

  error_messages_for 'user_common', 'user', :object_name => 'user'

If the objects cannot be located as instance variables, you can add an extra object paremeter which gives the actual object (or array of objects to use)

  error_messages_for 'user', :object => @question.user

NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors instance yourself and set it up. View the source of this method to see how easy it is.

[ show source ]

     # File actionpack/lib/action_view/helpers/active_record_helper.rb, line 131
131:       def error_messages_for(*params)
132:         options = params.extract_options!.symbolize_keys
133:         if object = options.delete(:object)
134:           objects = [object].flatten
135:         else
136:           objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
137:         end
138:         count   = objects.inject(0) {|sum, object| sum + object.errors.count }
139:         unless count.zero?
140:           html = {}
141:           [:id, :class].each do |key|
142:             if options.include?(key)
143:               value = options[key]
144:               html[key] = value unless value.blank?
145:             else
146:               html[key] = 'errorExplanation'
147:             end
148:           end
149:           options[:object_name] ||= params.first
150:           options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message)
151:           options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message)
152:           error_messages = objects.map {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }
153:
154:           contents = ''
155:           contents << content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank?
156:           contents << content_tag(:p, options[:message]) unless options[:message].blank?
157:           contents << content_tag(:ul, error_messages)
158:
159:           content_tag(:div, contents, html)
160:         else
161:           ''
162:         end
163:       end
form(record_name, options = {}) {|contents if block_given?| ...}

Returns an entire form with all needed input tags for a specified Active Record object. For example, let‘s say you have a table model Post with attributes named title of type VARCHAR and body of type TEXT:

  form("post")

That line would yield a form like the following:

    <form action='/post/create' method='post'>
      <p>
        <label for="post_title">Title</label><br />
        <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
      </p>
      <p>
        <label for="post_body">Body</label><br />
        <textarea cols="40" id="post_body" name="post[body]" rows="20">
        </textarea>
      </p>
      <input type='submit' value='Create' />
    </form>

It‘s possible to specialize the form builder by using a different action name and by supplying another block renderer. For example, let‘s say you have a model Entry with an attribute message of type VARCHAR:

  form("entry", :action => "sign", :input_block =>
       Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) =>

    <form action='/post/sign' method='post'>
      Message:
      <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /><br />
      <input type='submit' value='Sign' />
    </form>

It‘s also possible to add additional content to the form by giving it a block, such as:

  form("entry", :action => "sign") do |form|
    form << content_tag("b", "Department")
    form << collection_select("department", "id", @departments, "id", "name")
  end

[ show source ]

    # File actionpack/lib/action_view/helpers/active_record_helper.rb, line 59
59:       def form(record_name, options = {})
60:         record = instance_variable_get("@#{record_name}")
61:
62:         options = options.symbolize_keys
63:         options[:action] ||= record.new_record? ? "create" : "update"
64:         action = url_for(:action => options[:action], :id => record)
65:
66:         submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
67:
68:         contents = ''
69:         contents << hidden_field(record_name, :id) unless record.new_record?
70:         contents << all_input_tags(record, record_name, options)
71:         yield contents if block_given?
72:         contents << submit_tag(submit_value)
73:
74:         content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil)
75:       end
input(record_name, method, options = {})

Returns a default input tag for the type of object returned by the method. For example, let‘s say you have a model that has an attribute title of type VARCHAR column, and this instance holds "Hello World":

  input("post", "title") =>
    <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />

[ show source ]

    # File actionpack/lib/action_view/helpers/active_record_helper.rb, line 20
20:       def input(record_name, method, options = {})
21:         InstanceTag.new(record_name, method, self).to_tag(options)
22:       end


Module: ActionView::Helpers::AssetTagHelper

Module
ActionView::Helpers::AssetTagHelper
In: actionpack/lib/action_view/helpers/asset_tag_helper.rb

This module provides methods for generating HTML that links views to assets such as images, javascripts, stylesheets, and feeds. These methods do not verify the assets exist before linking to them.

Using asset hosts

By default, Rails links to these assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated assets server by setting ActionController::Base.asset_host in your environment.rb. For example, let‘s say your asset host is assets.example.com.

  ActionController::Base.asset_host = "assets.example.com"
  image_tag("rails.png")
    => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
  stylesheet_include_tag("application")
    => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />

This is useful since browsers typically open at most two connections to a single host, which means your assets often wait in single file for their turn to load. You can alleviate this by using a %d wildcard in asset_host (for example, "assets%d.example.com") to automatically distribute asset requests among four hosts (e.g., assets0.example.com through assets3.example.com) so browsers will open eight connections rather than two.

  image_tag("rails.png")
    => <img src="http://assets0.example.com/images/rails.png" alt="Rails" />
  stylesheet_include_tag("application")
    => <link href="http://assets3.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />

To do this, you can either setup 4 actual hosts, or you can use wildcard DNS to CNAME the wildcard to a single asset host. You can read more about setting up your DNS CNAME records from your ISP.

Note: This is purely a browser performance optimization and is not meant for server load balancing. See www.die.net/musings/page_load_time/ for background.

Alternatively, you can exert more control over the asset host by setting asset_host to a proc that takes a single source argument. This is useful if you are unable to setup 4 actual hosts or have fewer/more than 4 hosts. The example proc below generates assets1.example.com and assets2.example.com randomly.

  ActionController::Base.asset_host = Proc.new { |source| "http://assets#{rand(2) + 1}.example.com" }
  image_tag("rails.png")
    => <img src="http://assets2.example.com/images/rails.png" alt="Rails" />
  stylesheet_include_tag("application")
    => <link href="http://assets1.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />

The proc takes a single source parameter which is the path of the source asset. This can be used to generate a particular asset host depending on the asset path.

   ActionController::Base.asset_host = Proc.new { |source|
     if source.starts_with?('/images')
       "http://images.example.com"
     else
       "http://assets.example.com"
     end
   }
  image_tag("rails.png")
    => <img src="http://images.example.com/images/rails.png" alt="Rails" />
  stylesheet_include_tag("application")
    => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />

Using asset timestamps

By default, Rails will append all asset paths with that asset‘s timestamp. This allows you to set a cache-expiration date for the asset far into the future, but still be able to instantly invalidate it by simply updating the file (and hence updating the timestamp, which then updates the URL as the timestamp is part of that, which in turn busts the cache).

It‘s the responsibility of the web server you use to set the far-future expiration date on cache assets that you need to take advantage of this feature. Here‘s an example for Apache:

# Asset Expiration ExpiresActive On <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">

  ExpiresDefault "access plus 1 year"

</FilesMatch>

Also note that in order for this to work, all your application servers must return the same timestamps. This means that they must have their clocks synchronized. If one of them drift out of sync, you‘ll see different timestamps at random and the cache won‘t work. Which means that the browser will request the same assets over and over again even thought they didn‘t change. You can use something like Live HTTP Headers for Firefox to verify that the cache is indeed working (and that the assets are not being requested over and over).

Methods
  • auto_discovery_link_tag
  • image_path
  • image_tag
  • javascript_include_tag
  • javascript_path
  • path_to_image
  • path_to_javascript
  • path_to_stylesheet
  • register_javascript_include_default
  • stylesheet_link_tag
  • stylesheet_path
Constants
ASSETS_DIR | = | defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/public" : "public"
JAVASCRIPTS_DIR | = | "#{ASSETS_DIR}/javascripts"
STYLESHEETS_DIR | = | "#{ASSETS_DIR}/stylesheets"
JAVASCRIPT_DEFAULT_SOURCES | = | ['prototype', 'effects', 'dragdrop', 'controls'] unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
Public Class methods
register_javascript_include_default(*sources)

Register one or more additional JavaScript files to be included when javascript_include_tag :defaults is called. This method is typically intended to be called from plugin initialization to register additional .js files that the plugin installed in public/javascripts.

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 241
241:       def self.register_javascript_include_default(*sources)
242:         @@javascript_default_sources.concat(sources)
243:       end
Public Instance methods
auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})

Returns a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed. The type can either be :rss (default) or :atom. Control the link options in url_for format using the url_options. You can modify the LINK tag itself in tag_options.

Options:

  • :rel - Specify the relation of this link, defaults to "alternate"
  • :type - Override the auto-generated mime type
  • :title - Specify the title of the link, defaults to the type

Examples

 auto_discovery_link_tag # =>
    <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/action" />
 auto_discovery_link_tag(:atom) # =>
    <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.currenthost.com/controller/action" />
 auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
    <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/feed" />
 auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
    <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.currenthost.com/controller/feed" />
 auto_discovery_link_tag(:rss, {:controller => "news", :action => "feed"}) # =>
    <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/news/feed" />
 auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "Example RSS"}) # =>
    <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed" />

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 116
116:       def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
117:         tag(
118:           "link",
119:           "rel"   => tag_options[:rel] || "alternate",
120:           "type"  => tag_options[:type] || Mime::Type.lookup_by_extension(type.to_s).to_s,
121:           "title" => tag_options[:title] || type.to_s.upcase,
122:           "href"  => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options
123:         )
124:       end
image_path(source)

Computes the path to an image asset in the public images directory. Full paths from the document root will be passed through. Used internally by image_tag to build the image path.

Examples

  image_path("edit")                                         # => /images/edit
  image_path("edit.png")                                     # => /images/edit.png
  image_path("icons/edit.png")                               # => /images/icons/edit.png
  image_path("/icons/edit.png")                              # => /icons/edit.png
  image_path("http://www.railsapplication.com/img/edit.png") # => http://www.railsapplication.com/img/edit.png
This method is also aliased as path_to_image

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 344
344:       def image_path(source)
345:         compute_public_path(source, 'images')
346:       end
image_tag(source, options = {})

Returns an html image tag for the source. The source can be a full path or a file that exists in your public images directory.

Options

You can add HTML attributes using the options. The options supports three additional keys for convenience and conformance:

  • :alt - If no alt text is given, the file name part of the source is used (capitalized and without the extension)
  • :size - Supplied as "{Width}x{Height}", so "30x45" becomes width="30" and height="45". :size will be ignored if the value is not in the correct format.
  • :mouseover - Set an alternate image to be used when the onmouseover event is fired, and sets the original image to be replaced onmouseout. This can be used to implement an easy image toggle that fires on onmouseover.

Examples

 image_tag("icon")  # =>
   <img src="/images/icon" alt="Icon" />
 image_tag("icon.png")  # =>
   <img src="/images/icon.png" alt="Icon" />
 image_tag("icon.png", :size => "16x10", :alt => "Edit Entry")  # =>
   <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
 image_tag("/icons/icon.gif", :size => "16x16")  # =>
   <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
 image_tag("/icons/icon.gif", :height => '32', :width => '32') # =>
   <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
 image_tag("/icons/icon.gif", :class => "menu_icon") # =>
   <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />
 image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
   <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
 image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
   <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 382
382:       def image_tag(source, options = {})
383:         options.symbolize_keys!
384:
385:         options[:src] = path_to_image(source)
386:         options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
387:
388:         if size = options.delete(:size)
389:           options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
390:         end
391:
392:         if mouseover = options.delete(:mouseover)
393:           options[:onmouseover] = "this.src='#{image_path(mouseover)}'"
394:           options[:onmouseout]  = "this.src='#{image_path(options[:src])}'"
395:         end
396:
397:         tag("img", options)
398:       end
javascript_include_tag(*sources)

Returns an html script tag for each of the sources provided. You can pass in the filename (.js extension is optional) of javascript files that exist in your public/javascripts directory for inclusion into the current page or you can pass the full path relative to your document root. To include the Prototype and Scriptaculous javascript libraries in your application, pass :defaults as the source. When using :defaults, if an application.js file exists in your public javascripts directory, it will be included as well. You can modify the html attributes of the script tag by passing a hash as the last argument.

Examples

  javascript_include_tag "xmlhr" # =>
    <script type="text/javascript" src="/javascripts/xmlhr.js"></script>

  javascript_include_tag "xmlhr.js" # =>
    <script type="text/javascript" src="/javascripts/xmlhr.js"></script>

  javascript_include_tag "common.javascript", "/elsewhere/cools" # =>
    <script type="text/javascript" src="/javascripts/common.javascript"></script>
    <script type="text/javascript" src="/elsewhere/cools.js"></script>

  javascript_include_tag "http://www.railsapplication.com/xmlhr" # =>
    <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script>

  javascript_include_tag "http://www.railsapplication.com/xmlhr.js" # =>
    <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script>

  javascript_include_tag :defaults # =>
    <script type="text/javascript" src="/javascripts/prototype.js"></script>
    <script type="text/javascript" src="/javascripts/effects.js"></script>
    ...
    <script type="text/javascript" src="/javascripts/application.js"></script>
  • = The application.js file is only referenced if it exists

Though it‘s not really recommended practice, if you need to extend the default JavaScript set for any reason (e.g., you‘re going to be using a certain .js file in every action), then take a look at the register_javascript_include_default method.

You can also include all javascripts in the javascripts directory using :all as the source:

  javascript_include_tag :all # =>
    <script type="text/javascript" src="/javascripts/prototype.js"></script>
    <script type="text/javascript" src="/javascripts/effects.js"></script>
    ...
    <script type="text/javascript" src="/javascripts/application.js"></script>
    <script type="text/javascript" src="/javascripts/shop.js"></script>
    <script type="text/javascript" src="/javascripts/checkout.js"></script>

Note that the default javascript files will be included first. So Prototype and Scriptaculous are available to all subsequently included files.

Caching multiple javascripts into one

You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching is set to true (which is the case by default for the Rails production environment, but not for the development environment).

Examples

  javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
    <script type="text/javascript" src="/javascripts/prototype.js"></script>
    <script type="text/javascript" src="/javascripts/effects.js"></script>
    ...
    <script type="text/javascript" src="/javascripts/application.js"></script>
    <script type="text/javascript" src="/javascripts/shop.js"></script>
    <script type="text/javascript" src="/javascripts/checkout.js"></script>

  javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is true =>
    <script type="text/javascript" src="/javascripts/all.js"></script>

  javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is false =>
    <script type="text/javascript" src="/javascripts/prototype.js"></script>
    <script type="text/javascript" src="/javascripts/cart.js"></script>
    <script type="text/javascript" src="/javascripts/checkout.js"></script>

  javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is false =>
    <script type="text/javascript" src="/javascripts/shop.js"></script>

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 222
222:       def javascript_include_tag(*sources)
223:         options = sources.extract_options!.stringify_keys
224:         cache   = options.delete("cache")
225:
226:         if ActionController::Base.perform_caching && cache
227:           joined_javascript_name = (cache == true ? "all" : cache) + ".js"
228:           joined_javascript_path = File.join(JAVASCRIPTS_DIR, joined_javascript_name)
229:
230:           write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources))
231:           javascript_src_tag(joined_javascript_name, options)
232:         else
233:           expand_javascript_sources(sources).collect { |source| javascript_src_tag(source, options) }.join("\n")
234:         end
235:       end
javascript_path(source)

Computes the path to a javascript asset in the public javascripts directory. If the source filename has no extension, .js will be appended. Full paths from the document root will be passed through. Used internally by javascript_include_tag to build the script path.

Examples

  javascript_path "xmlhr" # => /javascripts/xmlhr.js
  javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
  javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
  javascript_path "http://www.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr.js
  javascript_path "http://www.railsapplication.com/js/xmlhr.js" # => http://www.railsapplication.com/js/xmlhr.js
This method is also aliased as path_to_javascript

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 137
137:       def javascript_path(source)
138:         compute_public_path(source, 'javascripts', 'js')
139:       end
path_to_image(source)

Alias for image_path

path_to_javascript(source)

Alias for javascript_path

path_to_stylesheet(source)

Alias for stylesheet_path

stylesheet_link_tag(*sources)

Returns a stylesheet link tag for the sources specified as arguments. If you don‘t specify an extension, .css will be appended automatically. You can modify the link attributes by passing a hash as the last argument.

Examples

  stylesheet_link_tag "style" # =>
    <link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "style.css" # =>
    <link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "http://www.railsapplication.com/style.css" # =>
    <link href="http://www.railsapplication.com/style.css" media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "style", :media => "all" # =>
    <link href="/stylesheets/style.css" media="all" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "style", :media => "print" # =>
    <link href="/stylesheets/style.css" media="print" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "random.styles", "/css/stylish" # =>
    <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" type="text/css" />
    <link href="/css/stylish.css" media="screen" rel="stylesheet" type="text/css" />

You can also include all styles in the stylesheet directory using :all as the source:

  stylesheet_link_tag :all # =>
    <link href="/stylesheets/style1.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/styleB.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" type="text/css" />

Caching multiple stylesheets into one

You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching is set to true (which is the case by default for the Rails production environment, but not for the development environment). Examples:

Examples

  stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
    <link href="/stylesheets/style1.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/styleB.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is true =>
    <link href="/stylesheets/all.css"  media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is false =>
    <link href="/stylesheets/shop.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/cart.css"  media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/checkout.css" media="screen" rel="stylesheet" type="text/css" />

  stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is true =>
    <link href="/stylesheets/payment.css"  media="screen" rel="stylesheet" type="text/css" />

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 319
319:       def stylesheet_link_tag(*sources)
320:         options = sources.extract_options!.stringify_keys
321:         cache   = options.delete("cache")
322:
323:         if ActionController::Base.perform_caching && cache
324:           joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"
325:           joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name)
326:
327:           write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources))
328:           stylesheet_tag(joined_stylesheet_name, options)
329:         else
330:           expand_stylesheet_sources(sources).collect { |source| stylesheet_tag(source, options) }.join("\n")
331:         end
332:       end
stylesheet_path(source)

Computes the path to a stylesheet asset in the public stylesheets directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path.

Examples

  stylesheet_path "style" # => /stylesheets/style.css
  stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
  stylesheet_path "/dir/style.css" # => /dir/style.css
  stylesheet_path "http://www.railsapplication.com/css/style" # => http://www.railsapplication.com/css/style.css
  stylesheet_path "http://www.railsapplication.com/css/style.js" # => http://www.railsapplication.com/css/style.css
This method is also aliased as path_to_stylesheet

[ show source ]

     # File actionpack/lib/action_view/helpers/asset_tag_helper.rb, line 260
260:       def stylesheet_path(source)
261:         compute_public_path(source, 'stylesheets', 'css')
262:       end


Module: ActionView::Helpers::AtomFeedHelper

Module
ActionView::Helpers::AtomFeedHelper
In: actionpack/lib/action_view/helpers/atom_feed_helper.rb
Methods
  • atom_feed
Classes and Modules
Class ActionView::Helpers::AtomFeedHelper::AtomFeedBuilder
Public Instance methods
atom_feed(options = {}) {|AtomFeedBuilder.new(xml, self)| ...}

Full usage example:

  config/routes.rb:
    ActionController::Routing::Routes.draw do |map|
      map.resources :posts
      map.root :controller => "posts"
    end

  app/controllers/posts_controller.rb:
    class PostsController < ApplicationController::Base
      # GET /posts.html
      # GET /posts.atom
      def index
        @posts = Post.find(:all)

        respond_to do |format|
          format.html
          format.atom
        end
      end
    end

  app/views/posts/index.atom.builder:
    atom_feed do |feed|
      feed.title("My great blog!")
      feed.updated((@posts.first.created_at))

      for post in @posts
        feed.entry(post) do |entry|
          entry.title(post.title)
          entry.content(post.body, :type => 'html')

          entry.author do |author|
            author.name("DHH")
          end
        end
      end
    end

The options are for atom_feed are:

  • :language: Defaults to "en-US".
  • :root_url: The HTML alternative that this feed is doubling for. Defaults to / on the current host.
  • :url: The URL for this feed. Defaults to the current URL.

atom_feed yields a AtomFeedBuilder instance.

[ show source ]

    # File actionpack/lib/action_view/helpers/atom_feed_helper.rb, line 52
52:       def atom_feed(options = {}, &block)
53:         xml = options[:xml] || eval("xml", block.binding)
54:         xml.instruct!
55:
56:         xml.feed "xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do
57:           xml.id("tag:#{request.host}:#{request.request_uri.split(".")[0].gsub("/", "")}")
58:           xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port))
59:
60:           if options[:url]
61:             xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url)
62:           end
63:
64:           yield AtomFeedBuilder.new(xml, self)
65:         end
66:       end


Class: ActionView::Helpers::AtomFeedHelper::AtomFeedBuilder

Class
ActionView::Helpers::AtomFeedHelper::AtomFeedBuilder
In: | actionpack/lib/action_view/helpers/atom_feed_helper.rb
Parent: | Object
Methods
  • entry
  • new
  • updated
Public Class methods
new(xml, view)

[ show source ]

    # File actionpack/lib/action_view/helpers/atom_feed_helper.rb, line 70
70:         def initialize(xml, view)
71:           @xml, @view = xml, view
72:         end
Public Instance methods
entry(record, options = {}) {|@xml| ...}

Creates an entry tag for a specific record and prefills the id using class and id.

Options:

  • :updated: Time of update. Defaults to the created_at attribute on the record if one such exists.
  • :published: Time first published. Defaults to the updated_at attribute on the record if one such exists.
  • :url: The URL for this entry. Defaults to the polymorphic_url for the record.

[ show source ]

     # File actionpack/lib/action_view/helpers/atom_feed_helper.rb, line 86
 86:         def entry(record, options = {})
 87:           @xml.entry do
 88:             @xml.id("tag:#{@view.request.host_with_port}:#{record.class}#{record.id}")
 89:
 90:             if options[:published] || (record.respond_to?(:created_at) && record.created_at)
 91:               @xml.published((options[:published] || record.created_at).xmlschema)
 92:             end
 93:
 94:             if options[:updated] || (record.respond_to?(:updated_at) && record.updated_at)
 95:               @xml.updated((options[:updated] || record.updated_at).xmlschema)
 96:             end
 97:
 98:             @xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:url] || @view.polymorphic_url(record))
 99:
100:             yield @xml
101:           end
102:         end
updated(date_or_time = nil)

Accepts a Date or Time object and inserts it in the proper format. If nil is passed, current time in UTC is used.

[ show source ]

    # File actionpack/lib/action_view/helpers/atom_feed_helper.rb, line 75
75:         def updated(date_or_time = nil)
76:           @xml.updated((date_or_time || Time.now.utc).xmlschema)
77:         end


Module: ActionView::Helpers::BenchmarkHelper

Module
ActionView::Helpers::BenchmarkHelper
In: actionpack/lib/action_view/helpers/benchmark_helper.rb

This helper offers a method to measure the execution time of a block in a template.

Methods
  • benchmark
Public Instance methods
benchmark(message = "Benchmarking", level = :info) {|| ...}

Allows you to measure the execution time of a block in a template and records the result to the log. Wrap this block around expensive operations or possible bottlenecks to get a time reading for the operation. For example, let‘s say you thought your file processing method was taking too long; you could wrap it in a benchmark block.

 <% benchmark "Process data files" do %>
   <%= expensive_files_operation %>
 <% end %>

That would add something like "Process data files (0.34523)" to the log, which you can then use to compare timings when optimizing your code.

You may give an optional logger level as the second argument (:debug, :info, :warn, :error); the default value is :info.

[ show source ]

    # File actionpack/lib/action_view/helpers/benchmark_helper.rb, line 23
23:       def benchmark(message = "Benchmarking", level = :info)
24:         if @logger
25:           real = Benchmark.realtime { yield }
26:           @logger.send level, "#{message} (#{'%.5f' % real})"
27:         end
28:       end


Module: ActionView::Helpers::CacheHelper

Module
ActionView::Helpers::CacheHelper
In: actionpack/lib/action_view/helpers/cache_helper.rb

This helper to exposes a method for caching of view fragments. See ActionController::Caching::Fragments for usage instructions.

Methods
  • cache
Public Instance methods
cache(name = {}, &block)

A method for caching fragments of a view rather than an entire action or page. This technique is useful caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See ActionController::Caching::Fragments for more information.

Examples

If you wanted to cache a navigation menu, you could do the following.

  <% cache do %>
    <%= render :partial => "menu" %>
  <% end %>

You can also cache static content…

  <% cache do %>
     <p>Hello users!  Welcome to our website!</p>
  <% end %>

…and static content mixed with RHTML content.

   <% cache do %>
     Topics:
     <%= render :partial => "topics", :collection => @topic_list %>
     <i>Topics listed alphabetically</i>
   <% end %>

[ show source ]

    # File actionpack/lib/action_view/helpers/cache_helper.rb, line 34
34:       def cache(name = {}, &block)
35:         @controller.cache_erb_fragment(block, name)
36:       end


Module: ActionView::Helpers::CaptureHelper

Module
ActionView::Helpers::CaptureHelper
In: actionpack/lib/action_view/helpers/capture_helper.rb

CaptureHelper exposes methods to let you extract generated markup which can be used in other parts of a template or layout file. It provides a method to capture blocks into variables through capture and a way to capture a block of markup for use in a layout through content_for.

Methods
  • capture
  • content_for
Public Instance methods
capture(*args, &block)

The capture method allows you to extract part of a template into a variable. You can then use this variable anywhere in your templates or layout.

Examples

The capture method can be used in ERb templates…

  <% @greeting = capture do %>
    Welcome to my shiny new web page!  The date and time is
    <%= Time.now %>
  <% end %>

…and Builder (RXML) templates.

  @timestamp = capture do
    "The current timestamp is #{Time.now}."
  end

You can then use that variable anywhere else. For example:

  <html>
  <head><title><%= @greeting %></title></head>
  <body>
  <b><%= @greeting %></b>
  </body></html>

[ show source ]

    # File actionpack/lib/action_view/helpers/capture_helper.rb, line 33
33:       def capture(*args, &block)
34:         # execute the block
35:         begin
36:           buffer = eval(ActionView::Base.erb_variable, block.binding)
37:         rescue
38:           buffer = nil
39:         end
40:
41:         if buffer.nil?
42:           capture_block(*args, &block).to_s
43:         else
44:           capture_erb_with_buffer(buffer, *args, &block).to_s
45:         end
46:       end
content_for(name, content = nil, &block)

Calling content_for stores a block of markup in an identifier for later use. You can make subsequent calls to the stored content in other templates or the layout by passing the identifier as an argument to yield.

Examples

  <% content_for :not_authorized do %>
    alert('You are not authorized to do that!')
  <% end %>

You can then use yield :not_authorized anywhere in your templates.

  <%= yield :not_authorized if current_user.nil? %>

You can also use this syntax alongside an existing call to yield in a layout. For example:

  <%# This is the layout %>
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>My Website</title>
    <%= yield :script %>
  </head>
  <body>
    <%= yield %>
  </body>
  </html>

And now, we‘ll create a view that has a content_for call that creates the script identifier.

  <%# This is our view %>
  Please login!

  <% content_for :script do %>
    <script type="text/javascript">alert('You are not authorized to view this page!')</script>
  <% end %>

Then, in another view, you could to do something like this:

  <%= link_to_remote 'Logout', :action => 'logout' %>

  <% content_for :script do %>
    <%= javascript_include_tag :defaults %>
  <% end %>

That will place <script> tags for Prototype, Scriptaculous, and application.js (if it exists) on the page; this technique is useful if you‘ll only be using these scripts in a few views.

Note that content_for concatenates the blocks it is given for a particular identifier in order. For example:

  <% content_for :navigation do %>
    <li><%= link_to 'Home', :action => 'index' %></li>
  <% end %>

  <%#  Add some other content, or use a different template: %>

  <% content_for :navigation do %>
    <li><%= link_to 'Login', :action => 'login' %></li>
  <% end %>

Then, in another template or layout, this code would render both links in order:

  <ul><%= yield :navigation %></ul>

Lastly, simple content can be passed as a parameter:

  <% content_for :script, javascript_include_tag(:defaults) %>

WARNING: content_for is ignored in caches. So you shouldn‘t use it for elements that will be fragment cached.

The deprecated way of accessing a content_for block is to use an instance variable named @content_for_#{name_of_the_content_block}. So <%= content_for :footer %> would be available as <%= @content_for_footer %>. The preferred usage is now <%= yield :footer %>.

[ show source ]

     # File actionpack/lib/action_view/helpers/capture_helper.rb, line 124
124:       def content_for(name, content = nil, &block)
125:         existing_content_for = instance_variable_get("@content_for_#{name}").to_s
126:         new_content_for      = existing_content_for + (block_given? ? capture(&block) : content)
127:         instance_variable_set("@content_for_#{name}", new_content_for)
128:       end


Module: ActionView::Helpers::DateHelper

Module
ActionView::Helpers::DateHelper
In: actionpack/lib/action_view/helpers/date_helper.rb

The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the select-type methods share a number of common options that are as follows:

  • :prefix - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give birthday[month] instead of date[month] if passed to the select_month method.
  • :include_blank - set to true if it should be possible to set an empty date.
  • :discard_type - set to true if you want to discard the type part of the select name. If set to true, the select_month method would use simply "date" (which can be overwritten using :prefix) instead of "date[month]".
Methods
  • date_select
  • datetime_select
  • distance_of_time_in_words
  • distance_of_time_in_words_to_now
  • select_date
  • select_datetime
  • select_day
  • select_hour
  • select_minute
  • select_month
  • select_second
  • select_time
  • select_year
  • time_ago_in_words
  • time_select
Constants
DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
Public Instance methods
date_select(object_name, method, options = {})

Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by method) on an object assigned to the template (identified by object). It‘s possible to tailor the selects through the options hash, which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of discard options. The discard options are :discard_year, :discard_month and :discard_day. Set to true, they‘ll drop the respective select. Discarding the month select will also automatically discard the day select. It‘s also possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month and :day in the desired order. Symbols may be omitted and the respective select is not included.

Pass the :default option to set the default date. Use a Time object or a Hash of :year, :month, :day, :hour, :minute, and :second.

Passing :disabled => true as part of the options will make elements inaccessible for change.

NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.

Examples

  # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
  date_select("post", "written_on")

  # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
  # with the year in the year drop down box starting at 1995.
  date_select("post", "written_on", :start_year => 1995)

  # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
  # with the year in the year drop down box starting at 1995, numbers used for months instead of words,
  # and without a day select box.
  date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
                                    :discard_day => true, :include_blank => true)

  # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
  # with the fields ordered as day, month, year rather than month, day, year.
  date_select("post", "written_on", :order => [:day, :month, :year])

  # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
  # lacking a year field.
  date_select("user", "birthday", :order => [:month, :day])

  # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
  # which is initially set to the date 3 days from the current date
  date_select("post", "written_on", :default => 3.days.from_now)

  # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
  # that will have a default day of 20.
  date_select("credit_card", "bill_due", :default => { :day => 20 })

The selects are prepared for multi-parameter assignment to an Active Record object.

Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month choices are valid.

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 151
151:       def date_select(object_name, method, options = {})
152:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options)
153:       end
datetime_select(object_name, method, options = {})

Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based attribute (identified by method) on an object assigned to the template (identified by object). Examples:

Examples

  # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
  datetime_select("post", "written_on")

  # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
  # post variable in the written_on attribute.
  datetime_select("post", "written_on", :start_year => 1995)

  # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will be stored in the
  # trip variable in the departing attribute.
  datetime_select("trip", "departing", :default => 3.days.from_now)

  # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable as the written_on
  # attribute.
  datetime_select("post", "written_on", :discard_type => true)

The selects are prepared for multi-parameter assignment to an Active Record object.

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 208
208:       def datetime_select(object_name, method, options = {})
209:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
210:       end
distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)

Reports the approximate distance in time between two Time or Date objects or integers as seconds. Set include_seconds to true if you want more detailed approximations when distance < 1 min, 29 secs Distances are reported base on the following table:

0 <-> 29 secs # => less than a minute 30 secs <-> 1 min, 29 secs # => 1 minute 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months 1 yr <-> 2 yrs minus 1 secs # => about 1 year 2 yrs <-> max time or date # => over [2..X] years

With include_seconds = true and the difference < 1 minute 29 seconds 0-4 secs # => less than 5 seconds 5-9 secs # => less than 10 seconds 10-19 secs # => less than 20 seconds 20-39 secs # => half a minute 40-59 secs # => less than a minute 60-89 secs # => 1 minute

Examples

  from_time = Time.now
  distance_of_time_in_words(from_time, from_time + 50.minutes)        # => about 1 hour
  distance_of_time_in_words(from_time, 50.minutes.from_now)           # => about 1 hour
  distance_of_time_in_words(from_time, from_time + 15.seconds)        # => less than a minute
  distance_of_time_in_words(from_time, from_time + 15.seconds, true)  # => less than 20 seconds
  distance_of_time_in_words(from_time, 3.years.from_now)              # => over 3 years
  distance_of_time_in_words(from_time, from_time + 60.hours)          # => about 3 days
  distance_of_time_in_words(from_time, from_time + 45.seconds, true)  # => less than a minute
  distance_of_time_in_words(from_time, from_time - 45.seconds, true)  # => less than a minute
  distance_of_time_in_words(from_time, 76.seconds.from_now)           # => 1 minute
  distance_of_time_in_words(from_time, from_time + 1.year + 3.days)   # => about 1 year
  distance_of_time_in_words(from_time, from_time + 4.years + 15.days + 30.minutes + 5.seconds) # => over 4 years

  to_time = Time.now + 6.years + 19.days
  distance_of_time_in_words(from_time, to_time, true)     # => over 6 years
  distance_of_time_in_words(to_time, from_time, true)     # => over 6 years
  distance_of_time_in_words(Time.now, Time.now)           # => less than a minute

[ show source ]

    # File actionpack/lib/action_view/helpers/date_helper.rb, line 59
59:       def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
60:         from_time = from_time.to_time if from_time.respond_to?(:to_time)
61:         to_time = to_time.to_time if to_time.respond_to?(:to_time)
62:         distance_in_minutes = (((to_time - from_time).abs)/60).round
63:         distance_in_seconds = ((to_time - from_time).abs).round
64:
65:         case distance_in_minutes
66:           when 0..1
67:             return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
68:             case distance_in_seconds
69:               when 0..4   then 'less than 5 seconds'
70:               when 5..9   then 'less than 10 seconds'
71:               when 10..19 then 'less than 20 seconds'
72:               when 20..39 then 'half a minute'
73:               when 40..59 then 'less than a minute'
74:               else             '1 minute'
75:             end
76:
77:           when 2..44           then "#{distance_in_minutes} minutes"
78:           when 45..89          then 'about 1 hour'
79:           when 90..1439        then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
80:           when 1440..2879      then '1 day'
81:           when 2880..43199     then "#{(distance_in_minutes / 1440).round} days"
82:           when 43200..86399    then 'about 1 month'
83:           when 86400..525599   then "#{(distance_in_minutes / 43200).round} months"
84:           when 525600..1051199 then 'about 1 year'
85:           else                      "over #{(distance_in_minutes / 525600).round} years"
86:         end
87:       end
distance_of_time_in_words_to_now(from_time, include_seconds = false)

Alias for time_ago_in_words

select_date(date = Date.today, options = {})

Returns a set of html select-tags (one for year, month, and day) pre-selected with the date. It‘s possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month and :day in the desired order. If you do not supply a Symbol, it will be appended onto the :order passed in.

Examples

  my_date = Time.today + 6.days

  # Generates a date select that defaults to the date in my_date (six days after today)
  select_date(my_date)

  # Generates a date select that defaults to today (no specified date)
  select_date()

  # Generates a date select that defaults to the date in my_date (six days after today)
  # with the fields ordered year, month, day rather than month, day, year.
  select_date(my_date, :order => [:year, :month, :day])

  # Generates a date select that discards the type of the field and defaults to the date in
  # my_date (six days after today)
  select_datetime(my_date_time, :discard_type => true)

  # Generates a date select that defaults to the datetime in my_date (six days after today)
  # prefixed with 'payday' rather than 'date'
  select_datetime(my_date_time, :prefix => 'payday')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 274
274:       def select_date(date = Date.today, options = {})
275:         options[:order] ||= []
276:         [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
277:
278:         select_date = ''
279:         options[:order].each do |o|
280:           select_date << self.send("select_#{o}", date, options)
281:         end
282:         select_date
283:       end
select_datetime(datetime = Time.now, options = {})

Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the datetime. It‘s also possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month and :day in the desired order. If you do not supply a Symbol, it will be appended onto the :order passed in. You can also add :date_separator and :time_separator keys to the options to control visual display of the elements.

Examples

  my_date_time = Time.now + 4.days

  # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
  select_datetime(my_date_time)

  # Generates a datetime select that defaults to today (no specified datetime)
  select_datetime()

  # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
  # with the fields ordered year, month, day rather than month, day, year.
  select_datetime(my_date_time, :order => [:year, :month, :day])

  # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
  # with a '/' between each date field.
  select_datetime(my_date_time, :date_separator => '/')

  # Generates a datetime select that discards the type of the field and defaults to the datetime in
  # my_date_time (four days after today)
  select_datetime(my_date_time, :discard_type => true)

  # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
  # prefixed with 'payday' rather than 'date'
  select_datetime(my_date_time, :prefix => 'payday')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 243
243:       def select_datetime(datetime = Time.now, options = {})
244:         separator = options[:datetime_separator] || ''
245:         select_date(datetime, options) + separator + select_time(datetime, options)
246:        end
select_day(date, options = {})

Returns a select tag with options for each of the days 1 through 31 with the current day selected. The date can also be substituted for a hour number. Override the field name using the :field_name option, ‘day’ by default.

Examples

  my_date = Time.today + 2.days

  # Generates a select field for days that defaults to the day for the date in my_date
  select_day(my_time)

  # Generates a select field for days that defaults to the number given
  select_day(5)

  # Generates a select field for days that defaults to the day for the date in my_date
  # that is named 'due' rather than 'day'
  select_day(my_time, :field_name => 'due')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 432
432:       def select_day(date, options = {})
433:         val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
434:         if options[:use_hidden]
435:           hidden_html(options[:field_name] || 'day', val, options)
436:         else
437:           day_options = []
438:           1.upto(31) do |day|
439:             day_options << ((val == day) ?
440:               %(<option value="#{day}" selected="selected">#{day}</option>\n) :
441:               %(<option value="#{day}">#{day}</option>\n)
442:             )
443:           end
444:           select_html(options[:field_name] || 'day', day_options, options)
445:         end
446:       end
select_hour(datetime, options = {})

Returns a select tag with options for each of the hours 0 through 23 with the current hour selected. The hour can also be substituted for a hour number. Override the field name using the :field_name option, ‘hour’ by default.

Examples

  my_time = Time.now + 6.hours

  # Generates a select field for minutes that defaults to the minutes for the time in my_time
  select_minute(my_time)

  # Generates a select field for minutes that defaults to the number given
  select_minute(14)

  # Generates a select field for minutes that defaults to the minutes for the time in my_time
  # that is named 'stride' rather than 'second'
  select_minute(my_time, :field_name => 'stride')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 399
399:       def select_hour(datetime, options = {})
400:         val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
401:         if options[:use_hidden]
402:           hidden_html(options[:field_name] || 'hour', val, options)
403:         else
404:           hour_options = []
405:           0.upto(23) do |hour|
406:             hour_options << ((val == hour) ?
407:               %(<option value="#{leading_zero_on_single_digits(hour)}" selected="selected">#{leading_zero_on_single_digits(hour)}</option>\n) :
408:               %(<option value="#{leading_zero_on_single_digits(hour)}">#{leading_zero_on_single_digits(hour)}</option>\n)
409:             )
410:           end
411:           select_html(options[:field_name] || 'hour', hour_options, options)
412:         end
413:       end
select_minute(datetime, options = {})

Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected. Also can return a select tag with options by minute_step from 0 through 59 with the 00 minute selected The minute can also be substituted for a minute number. Override the field name using the :field_name option, ‘minute’ by default.

Examples

  my_time = Time.now + 6.hours

  # Generates a select field for minutes that defaults to the minutes for the time in my_time
  select_minute(my_time)

  # Generates a select field for minutes that defaults to the number given
  select_minute(14)

  # Generates a select field for minutes that defaults to the minutes for the time in my_time
  # that is named 'stride' rather than 'second'
  select_minute(my_time, :field_name => 'stride')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 366
366:       def select_minute(datetime, options = {})
367:         val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
368:         if options[:use_hidden]
369:           hidden_html(options[:field_name] || 'minute', val, options)
370:         else
371:           minute_options = []
372:           0.step(59, options[:minute_step] || 1) do |minute|
373:             minute_options << ((val == minute) ?
374:               %(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
375:               %(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
376:             )
377:           end
378:           select_html(options[:field_name] || 'minute', minute_options, options)
379:          end
380:       end
select_month(date, options = {})

Returns a select tag with options for each of the months January through December with the current month selected. The month names are presented as keys (what‘s shown to the user) and the month numbers (1-12) are used as values (what‘s submitted to the server). It‘s also possible to use month numbers for the presentation instead of names — set the :use_month_numbers key in options to true for this to happen. If you want both numbers and names, set the :add_month_numbers key in options to true. If you would prefer to show month names as abbreviations, set the :use_short_month key in options to true. If you want to use your own month names, set the :use_month_names key in options to an array of 12 month names. Override the field name using the :field_name option, ‘month’ by default.

Examples

  # Generates a select field for months that defaults to the current month that
  # will use keys like "January", "March".
  select_month(Date.today)

  # Generates a select field for months that defaults to the current month that
  # is named "start" rather than "month"
  select_month(Date.today, :field_name => 'start')

  # Generates a select field for months that defaults to the current month that
  # will use keys like "1", "3".
  select_month(Date.today, :use_month_numbers => true)

  # Generates a select field for months that defaults to the current month that
  # will use keys like "1 - January", "3 - March".
  select_month(Date.today, :add_month_numbers => true)

  # Generates a select field for months that defaults to the current month that
  # will use keys like "Jan", "Mar".
  select_month(Date.today, :use_short_month => true)

  # Generates a select field for months that defaults to the current month that
  # will use keys like "Januar", "Marts."
  select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 482
482:       def select_month(date, options = {})
483:         val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
484:         if options[:use_hidden]
485:           hidden_html(options[:field_name] || 'month', val, options)
486:         else
487:           month_options = []
488:           month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
489:           month_names.unshift(nil) if month_names.size < 13
490:           1.upto(12) do |month_number|
491:             month_name = if options[:use_month_numbers]
492:               month_number
493:             elsif options[:add_month_numbers]
494:               month_number.to_s + ' - ' + month_names[month_number]
495:             else
496:               month_names[month_number]
497:             end
498:
499:             month_options << ((val == month_number) ?
500:               %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
501:               %(<option value="#{month_number}">#{month_name}</option>\n)
502:             )
503:           end
504:           select_html(options[:field_name] || 'month', month_options, options)
505:         end
506:       end
select_second(datetime, options = {})

Returns a select tag with options for each of the seconds 0 through 59 with the current second selected. The second can also be substituted for a second number. Override the field name using the :field_name option, ‘second’ by default.

Examples

  my_time = Time.now + 16.minutes

  # Generates a select field for seconds that defaults to the seconds for the time in my_time
  select_second(my_time)

  # Generates a select field for seconds that defaults to the number given
  select_second(33)

  # Generates a select field for seconds that defaults to the seconds for the time in my_time
  # that is named 'interval' rather than 'second'
  select_second(my_time, :field_name => 'interval')

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 332
332:       def select_second(datetime, options = {})
333:         val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
334:         if options[:use_hidden]
335:           options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : ''
336:         else
337:           second_options = []
338:           0.upto(59) do |second|
339:             second_options << ((val == second) ?
340:               %(<option value="#{leading_zero_on_single_digits(second)}" selected="selected">#{leading_zero_on_single_digits(second)}</option>\n) :
341:               %(<option value="#{leading_zero_on_single_digits(second)}">#{leading_zero_on_single_digits(second)}</option>\n)
342:             )
343:           end
344:           select_html(options[:field_name] || 'second', second_options, options)
345:         end
346:       end
select_time(datetime = Time.now, options = {})

Returns a set of html select-tags (one for hour and minute) You can set :time_separator key to format the output, and the :include_seconds option to include an input for seconds.

Examples

  my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds

  # Generates a time select that defaults to the time in my_time
  select_time(my_time)

  # Generates a time select that defaults to the current time (no specified time)
  select_time()

  # Generates a time select that defaults to the time in my_time,
  # which has fields separated by ':'
  select_time(my_time, :time_separator => ':')

  # Generates a time select that defaults to the time in my_time,
  # that also includes an input for seconds
  select_time(my_time, :include_seconds => true)

  # Generates a time select that defaults to the time in my_time, that has fields
  # separated by ':' and includes an input for seconds
  select_time(my_time, :time_separator => ':', :include_seconds => true)

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 310
310:       def select_time(datetime = Time.now, options = {})
311:         separator = options[:time_separator] || ''
312:         select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '')
313:       end
select_year(date, options = {})

Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius can be changed using the :start_year and :end_year keys in the options. Both ascending and descending year lists are supported by making :start_year less than or greater than :end_year. The date can also be substituted for a year given as a number. Override the field name using the :field_name option, ‘year’ by default.

Examples

  # Generates a select field for years that defaults to the current year that
  # has ascending year values
  select_year(Date.today, :start_year => 1992, :end_year => 2007)

  # Generates a select field for years that defaults to the current year that
  # is named 'birth' rather than 'year'
  select_year(Date.today, :field_name => 'birth')

  # Generates a select field for years that defaults to the current year that
  # has descending year values
  select_year(Date.today, :start_year => 2005, :end_year => 1900)

  # Generates a select field for years that defaults to the year 2006 that
  # has ascending year values
  select_year(2006, :start_year => 2000, :end_year => 2010)

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 530
530:       def select_year(date, options = {})
531:         val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
532:         if options[:use_hidden]
533:           hidden_html(options[:field_name] || 'year', val, options)
534:         else
535:           year_options = []
536:           y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
537:
538:           start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
539:           step_val = start_year < end_year ? 1 : -1
540:           start_year.step(end_year, step_val) do |year|
541:             year_options << ((val == year) ?
542:               %(<option value="#{year}" selected="selected">#{year}</option>\n) :
543:               %(<option value="#{year}">#{year}</option>\n)
544:             )
545:           end
546:           select_html(options[:field_name] || 'year', year_options, options)
547:         end
548:       end
time_ago_in_words(from_time, include_seconds = false)

Like distance_of_time_in_words, but where to_time is fixed to Time.now.

Examples

  time_ago_in_words(3.minutes.from_now)       # => 3 minutes
  time_ago_in_words(Time.now - 15.hours)      # => 15 hours
  time_ago_in_words(Time.now)                 # => less than a minute

  from_time = Time.now - 3.days - 14.minutes - 25.seconds     # => 3 days
This method is also aliased as distance_of_time_in_words_to_now

[ show source ]

    # File actionpack/lib/action_view/helpers/date_helper.rb, line 97
97:       def time_ago_in_words(from_time, include_seconds = false)
98:         distance_of_time_in_words(from_time, Time.now, include_seconds)
99:       end
time_select(object_name, method, options = {})

Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified time-based attribute (identified by method) on an object assigned to the template (identified by object). You can include the seconds with :include_seconds.

Examples

  # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
  time_select("post", "sunrise")

  # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute
  time_select("order", "submitted")

  # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute
  time_select("mail", "sent_at")

  # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
  # the sunrise attribute.
  time_select("post", "start_time", :include_seconds => true)

  # Creates a time select tag with a seconds field that, when POSTed, will be stored in the entry variables in
  # the submission_time attribute.
  time_select("entry", "submission_time", :include_seconds => true)

  # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
  time_select 'game', 'game_time', {:minute_step => 15}

The selects are prepared for multi-parameter assignment to an Active Record object.

Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month choices are valid.

[ show source ]

     # File actionpack/lib/action_view/helpers/date_helper.rb, line 184
184:       def time_select(object_name, method, options = {})
185:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options)
186:       end


Module: ActionView::Helpers::DebugHelper

Module
ActionView::Helpers::DebugHelper
In: actionpack/lib/action_view/helpers/debug_helper.rb

Provides a set of methods for making it easier to debug Rails objects.

Methods
  • debug
Public Instance methods
debug(object)

Returns a <pre>-tag that has object dumped by YAML. This creates a very readable way to inspect an object.

Example

 my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
 debug(my_hash)

 => <pre class='debug_dump'>---
 first: 1
 second: two
 third:
 - 1
 - 2
 - 3
 </pre>

[ show source ]

    # File actionpack/lib/action_view/helpers/debug_helper.rb, line 20
20:       def debug(object)
21:         begin
22:           Marshal::dump(object)
23:           "<pre class='debug_dump'>#{h(object.to_yaml).gsub("  ", "&nbsp; ")}</pre>"
24:         rescue Exception => e  # errors from Marshal or YAML
25:           # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
26:           "<code class='debug_dump'>#{h(object.inspect)}</code>"
27:         end
28:       end


Module: ActionView::Helpers::FormHelper

Module
ActionView::Helpers::FormHelper
In: actionpack/lib/action_view/helpers/form_helper.rb

Form helpers are designed to make working with models much easier compared to using just standard HTML elements by providing a set of methods for creating forms based on your models. This helper generates the HTML for forms, providing a method for each sort of input (e.g., text, password, select, and so on). When the form is submitted (i.e., when the user hits the submit button or form.submit is called via JavaScript), the form inputs will be bundled into the params object and passed back to the controller.

There are two types of form helpers: those that specifically work with model attributes and those that don‘t. This helper deals with those that work with model attributes; to see an example of form helpers that don‘t work with model attributes, check the ActionView::Helpers::FormTagHelper documentation.

The core method of this helper, form_for, gives you the ability to create a form for a model instance; for example, let‘s say that you have a model Person and want to create a new instance of it:

    # Note: a @person variable will have been created in the controller.
    # For example: @person = Person.new
    <% form_for :person, @person, :url => { :action => "create" } do |f| %>
      <%= f.text_field :first_name %>
      <%= f.text_field :last_name %>
      <%= submit_tag 'Create' %>
    <% end %>

The HTML generated for this would be:

    <form action="/persons/create" method="post">
      <input id="person_first_name" name="person[first_name]" size="30" type="text" />
      <input id="person_last_name" name="person[last_name]" size="30" type="text" />
      <input name="commit" type="submit" value="Create" />
    </form>

The params object created when this form is submitted would look like:

    {"action"=>"create", "controller"=>"persons", "person"=>{"first_name"=>"William", "last_name"=>"Smith"}}

The params hash has a nested person value, which can therefore be accessed with params[:person] in the controller. If were editing/updating an instance (e.g., Person.find(1) rather than Person.new in the controller), the objects attribute values are filled into the form (e.g., the person_first_name field would have that person‘s first name in it).

If the object name contains square brackets the id for the object will be inserted. For example:

  <%= text_field "person[]", "name" %>

…will generate the following ERb.

  <input type="text" id="person_<%= @person.id %>_name" name="person[<%= @person.id %>][name]" value="<%= @person.name %>" />

If the helper is being used to generate a repetitive sequence of similar form elements, for example in a partial used by render_collection_of_partials, the index option may come in handy. Example:

  <%= text_field "person", "name", "index" => 1 %>

…becomes…

  <input type="text" id="person_1_name" name="person[1][name]" value="<%= @person.name %>" />

There are also methods for helping to build form tags in classes/ActionView/Helpers/FormOptionsHelper.html, classes/ActionView/Helpers/DateHelper.html, and classes/ActionView/Helpers/ActiveRecordHelper.html

Methods
  • check_box
  • fields_for
  • file_field
  • form_for
  • hidden_field
  • label
  • password_field
  • radio_button
  • text_area
  • text_field
Public Instance methods
check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")

Returns a checkbox tag tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). It‘s intended that method returns an integer and if that integer is above zero, then the checkbox is checked. Additional options on the input tag can be passed as a hash with options. The checked_value defaults to 1 while the default unchecked_value is set to 0 which is convenient for boolean values. Since HTTP standards say that unchecked checkboxes don‘t post anything, we add a hidden value with the same name as the checkbox as a work around.

Examples

  # Let's say that @post.validated? is 1:
  check_box("post", "validated")
  # => <input type="checkbox" id="post_validate" name="post[validated]" value="1" checked="checked" />
  #    <input name="post[validated]" type="hidden" value="0" />

  # Let's say that @puppy.gooddog is "no":
  check_box("puppy", "gooddog", {}, "yes", "no")
  # => <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
  #    <input name="puppy[gooddog]" type="hidden" value="no" />

  check_box("eula", "accepted", {}, "yes", "no", :class => 'eula_check')
  # => <input type="checkbox" id="eula_accepted" name="eula[accepted]" value="no" />
  #    <input name="eula[accepted]" type="hidden" value="no" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 401
401:       def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
402:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
403:       end
fields_for(record_or_name_or_array, *args) {|builder.new(object_name, object, self, options, block)| ...}

Creates a scope around a specific model object like form_for, but doesn‘t create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form:

Examples

  <% form_for @person, :url => { :action => "update" } do |person_form| %>
    First name: <%= person_form.text_field :first_name %>
    Last name : <%= person_form.text_field :last_name %>

    <% fields_for @person.permission do |permission_fields| %>
      Admin?  : <%= permission_fields.check_box :admin %>
    <% end %>
  <% end %>

…or if you have an object that needs to be represented as a different parameter, like a Client that acts as a Person:

  <% fields_for :person, @client do |permission_fields| %>
    Admin?: <%= permission_fields.check_box :admin %>
  <% end %>

…or if you don‘t have an object, just a name of the parameter

  <% fields_for :person do |permission_fields| %>
    Admin?: <%= permission_fields.check_box :admin %>
  <% end %>

Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, like FormOptionHelper#collection_select and DateHelper#datetime_select.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 230
230:       def fields_for(record_or_name_or_array, *args, &block)
231:         raise ArgumentError, "Missing block" unless block_given?
232:         options = args.extract_options!
233:
234:         case record_or_name_or_array
235:         when String, Symbol
236:           object_name = record_or_name_or_array
237:           object = args.first
238:         when Array
239:           object = record_or_name_or_array.last
240:           object_name = ActionController::RecordIdentifier.singular_class_name(object)
241:           apply_form_for_options!(record_or_name_or_array, options)
242:         else
243:           object = record_or_name_or_array
244:           object_name = ActionController::RecordIdentifier.singular_class_name(object)
245:         end
246:
247:         builder = options[:builder] || ActionView::Base.default_form_builder
248:         yield builder.new(object_name, object, self, options, block)
249:       end
file_field(object_name, method, options = {})

Returns an file upload input tag tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). Additional options on the input tag can be passed as a hash with options. These options will be tagged onto the HTML as an HTML element attribute as in the example shown.

Examples

  file_field(:user, :avatar)
  # => <input type="file" id="user_avatar" name="user[avatar]" />

  file_field(:post, :attached, :accept => 'text/html')
  # => <input type="file" id="post_attached" name="post[attached]" />

  file_field(:attachment, :file, :class => 'file_input')
  # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 347
347:       def file_field(object_name, method, options = {})
348:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("file", options)
349:       end
form_for(record_or_name_or_array, *args, &proc)

Creates a form and a scope around a specific model object that is used as a base for questioning about values for the fields.

  <% form_for :person, @person, :url => { :action => "update" } do |f| %>
    First name: <%= f.text_field :first_name %>
    Last name : <%= f.text_field :last_name %>
    Biography : <%= f.text_area :biography %>
    Admin?    : <%= f.check_box :admin %>
  <% end %>

Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that‘s <% %>, not <%= %>. Also worth noting is that form_for yields a form_builder object, in this example as f, which emulates the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, you get away with f.text_field :name.

Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone approach would require text_field :person, :name, :object => person to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with :person, person and all subsequent field calls save :person and :object => person.

Also note that form_for doesn‘t create an exclusive scope. It‘s still possible to use both the stand-alone FormHelper methods and methods from FormTagHelper. For example:

  <% form_for :person, @person, :url => { :action => "update" } do |f| %>
    First name: <%= f.text_field :first_name %>
    Last name : <%= f.text_field :last_name %>
    Biography : <%= text_area :person, :biography %>
    Admin?    : <%= check_box_tag "person[admin]", @person.company.admin? %>
  <% end %>

Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, like FormOptionHelper#collection_select and DateHelper#datetime_select.

HTML attributes for the form tag can be given as :html => {…}. For example:

  <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %>
    ...
  <% end %>

The above form will then have the id attribute with the value </tt>person_form</tt>, which you can then style with CSS or manipulate with JavaScript.

Relying on record identification

In addition to manually configuring the form_for call, you can also rely on record identification, which will use the conventions and named routes of that approach. Examples:

  <% form_for(@post) do |f| %>
    ...
  <% end %>

This will expand to be the same as:

  <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
    ...
  <% end %>

And for new records:

  <% form_for(Post.new) do |f| %>
    ...
  <% end %>

This will expand to be the same as:

  <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %>
    ...
  <% end %>

You can also overwrite the individual conventions, like this:

  <% form_for(@post, :url => super_post_path(@post)) do |f| %>
    ...
  <% end %>

And for namespaced routes, like admin_post_url:

  <% form_for([:admin, @post]) do |f| %>
   ...
  <% end %>

Customized form builders

You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers, then use your custom builder. For example, let‘s say you made a helper to automatically add labels to form inputs.

  <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
    <%= f.text_field :first_name %>
    <%= f.text_field :last_name %>
    <%= text_area :person, :biography %>
    <%= check_box_tag "person[admin]", @person.company.admin? %>
  <% end %>

In many cases you will want to wrap the above in another helper, so you could do something like the following:

  def labelled_form_for(name, object, options, &proc)
    form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc)
  end

If you don‘t need to attach a form to a model instance, then check out FormTagHelper#form_tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 163
163:       def form_for(record_or_name_or_array, *args, &proc)
164:         raise ArgumentError, "Missing block" unless block_given?
165:
166:         options = args.extract_options!
167:
168:         case record_or_name_or_array
169:         when String, Symbol
170:           object_name = record_or_name_or_array
171:         when Array
172:           object = record_or_name_or_array.last
173:           object_name = ActionController::RecordIdentifier.singular_class_name(object)
174:           apply_form_for_options!(record_or_name_or_array, options)
175:           args.unshift object
176:         else
177:           object = record_or_name_or_array
178:           object_name = ActionController::RecordIdentifier.singular_class_name(object)
179:           apply_form_for_options!([object], options)
180:           args.unshift object
181:         end
182:
183:         concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding)
184:         fields_for(object_name, *(args << options), &proc)
185:         concat('</form>', proc.binding)
186:       end
hidden_field(object_name, method, options = {})

Returns a hidden input tag tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). Additional options on the input tag can be passed as a hash with options. These options will be tagged onto the HTML as an HTML element attribute as in the example shown.

Examples

  hidden_field(:signup, :pass_confirm)
  # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="#{@signup.pass_confirm}" />

  hidden_field(:post, :tag_list)
  # => <input type="hidden" id="post_tag_list" name="post[tag_list]" value="#{@post.tag_list}" />

  hidden_field(:user, :token)
  # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 328
328:       def hidden_field(object_name, method, options = {})
329:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("hidden", options)
330:       end
label(object_name, method, text = nil, options = {})

Returns a label tag tailored for labelling an input field for a specified attribute (identified by method) on an object assigned to the template (identified by object). The text of label will default to the attribute name unless you specify it explicitly. Additional options on the label tag can be passed as a hash with options. These options will be tagged onto the HTML as an HTML element attribute as in the example shown.

Examples

  label(:post, :title)
  #=> <label for="post_title">Title</label>

  label(:post, :title, "A short title")
  #=> <label for="post_title">A short title</label>

  label(:post, :title, "A short title", :class => "title_label")
  #=> <label for="post_title" class="title_label">A short title</label>

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 266
266:       def label(object_name, method, text = nil, options = {})
267:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_label_tag(text, options)
268:       end
password_field(object_name, method, options = {})

Returns an input tag of the "password" type tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). Additional options on the input tag can be passed as a hash with options. These options will be tagged onto the HTML as an HTML element attribute as in the example shown.

Examples

  password_field(:login, :pass, :size => 20)
  # => <input type="text" id="login_pass" name="login[pass]" size="20" value="#{@login.pass}" />

  password_field(:account, :secret, :class => "form_input")
  # => <input type="text" id="account_secret" name="account[secret]" value="#{@account.secret}" class="form_input" />

  password_field(:user, :password, :onchange => "if $('user[password]').length > 30 { alert('Your password needs to be shorter!'); }")
  # => <input type="text" id="user_password" name="user[password]" value="#{@user.password}" onchange = "if $('user[password]').length > 30 { alert('Your password needs to be shorter!'); }"/>

  password_field(:account, :pin, :size => 20, :class => 'form_input')
  # => <input type="text" id="account_pin" name="account[pin]" size="20" value="#{@account.pin}" class="form_input" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 310
310:       def password_field(object_name, method, options = {})
311:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("password", options)
312:       end
radio_button(object_name, method, tag_value, options = {})

Returns a radio button tag for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). If the current value of method is tag_value the radio button will be checked. Additional options on the input tag can be passed as a hash with options.

Examples

  # Let's say that @post.category returns "rails":
  radio_button("post", "category", "rails")
  radio_button("post", "category", "java")
  # => <input type="radio" id="post_category" name="post[category]" value="rails" checked="checked" />
  #    <input type="radio" id="post_category" name="post[category]" value="java" />

  radio_button("user", "receive_newsletter", "yes")
  radio_button("user", "receive_newsletter", "no")
  # => <input type="radio" id="user_receive_newsletter" name="user[receive_newsletter]" value="yes" />
  #    <input type="radio" id="user_receive_newsletter" name="user[receive_newsletter]" value="no" checked="checked" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 421
421:       def radio_button(object_name, method, tag_value, options = {})
422:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_radio_button_tag(tag_value, options)
423:       end
text_area(object_name, method, options = {})

Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). Additional options on the input tag can be passed as a hash with options.

Examples

  text_area(:post, :body, :cols => 20, :rows => 40)
  # => <textarea cols="20" rows="40" id="post_body" name="post[body]">
  #      #{@post.body}
  #    </textarea>

  text_area(:comment, :text, :size => "20x30")
  # => <textarea cols="20" rows="30" id="comment_text" name="comment[text]">
  #      #{@comment.text}
  #    </textarea>

  text_area(:application, :notes, :cols => 40, :rows => 15, :class => 'app_input')
  # => <textarea cols="40" rows="15" id="application_notes" name="application[notes]" class="app_input">
  #      #{@application.notes}
  #    </textarea>

  text_area(:entry, :body, :size => "20x20", :disabled => 'disabled')
  # => <textarea cols="20" rows="20" id="entry_body" name="entry[body]" disabled="disabled">
  #      #{@entry.body}
  #    </textarea>

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 375
375:       def text_area(object_name, method, options = {})
376:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_text_area_tag(options)
377:       end
text_field(object_name, method, options = {})

Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by method) on an object assigned to the template (identified by object). Additional options on the input tag can be passed as a hash with options. These options will be tagged onto the HTML as an HTML element attribute as in the example shown.

Examples

  text_field(:post, :title, :size => 20)
  # => <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" />

  text_field(:post, :title, :class => "create_input")
  # => <input type="text" id="post_title" name="post[title]" value="#{@post.title}" class="create_input" />

  text_field(:session, :user, :onchange => "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }")
  # => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange = "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }"/>

  text_field(:snippet, :code, :size => 20, :class => 'code_input')
  # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_helper.rb, line 288
288:       def text_field(object_name, method, options = {})
289:         InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options)
290:       end


Module: ActionView::Helpers::FormOptionsHelper

Module
ActionView::Helpers::FormOptionsHelper
In: actionpack/lib/action_view/helpers/form_options_helper.rb

Provides a number of methods for turning different kinds of containers into a set of option tags.

Options

The collection_select, country_select, select, and time_zone_select methods take an options parameter, a hash.

  • :include_blank - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.

For example,

  select("post", "category", Post::CATEGORIES, {:include_blank => true})

could become:

  <select name="post[category]">
    <option></option>
    <option>joke</option>
    <option>poem</option>
  </select>

Another common case is a select tag for an belongs_to-associated object.

Example with @post.person_id => 2:

  select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, {:include_blank => 'None'})

could become:

  <select name="post[person_id]">
    <option value="">None</option>
    <option value="1">David</option>
    <option value="2" selected="selected">Sam</option>
    <option value="3">Tobias</option>
  </select>
  • :prompt - set to true or a prompt string. When the select element doesn‘t have a value yet, this prepends an option with a generic prompt — "Please select" — or the given prompt string.

Example:

  select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, {:prompt => 'Select Person'})

could become:

  <select name="post[person_id]">
    <option value="">Select Person</option>
    <option value="1">David</option>
    <option value="2">Sam</option>
    <option value="3">Tobias</option>
  </select>
Methods
  • collection_select
  • country_options_for_select
  • country_select
  • option_groups_from_collection_for_select
  • options_for_select
  • options_from_collection_for_select
  • select
  • time_zone_options_for_select
  • time_zone_select
Included Modules
  • ERB::Util
Constants
COUNTRIES = ["Afghanistan", "Aland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Holy See (Vatican City State)", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, The Former Yugoslav Republic Of", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of", "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Palestinian Territory, Occupied", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda", "Saint Barthelemy", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic", "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara", "Yemen", "Zambia", "Zimbabwe"] unless const_defined?("COUNTRIES")
All the countries included in the country_options output.
Public Instance methods
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})

Returns <select> and <option> tags for the collection of existing return values of method for object‘s class. The value returned from calling method on the instance object will be selected. If calling method returns nil, no selection is made without including :prompt or :include_blank in the options hash.

The :value_method and :text_method parameters are methods to be called on each member of collection. The return values are used as the value attribute and contents of each <option> tag, respectively.

Example object structure for use with this method:

  class Post < ActiveRecord::Base
    belongs_to :author
  end
  class Author < ActiveRecord::Base
    has_many :posts
    def name_with_initial
      "#{first_name.first}. #{last_name}"
    end
  end

Sample usage (selecting the associated Author for an instance of Post, @post):

  collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true})

If @post.author_id is already 1, this would return:

  <select name="post[author_id]">
    <option value="">Please select</option>
    <option value="1" selected="selected">D. Heinemeier Hansson</option>
    <option value="2">D. Thomas</option>
    <option value="3">M. Clark</option>
  </select>

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 117
117:       def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
118:         InstanceTag.new(object, method, self, nil, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
119:       end
country_options_for_select(selected = nil, priority_countries = nil)

Returns a string of option tags for pretty much any country in the world. Supply a country name as selected to have it marked as the selected option tag. You can also supply an array of countries as priority_countries, so that they will be listed above the rest of the (long) list.

NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 247
247:       def country_options_for_select(selected = nil, priority_countries = nil)
248:         country_options = ""
249:
250:         if priority_countries
251:           country_options += options_for_select(priority_countries, selected)
252:           country_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
253:         end
254:
255:         return country_options + options_for_select(COUNTRIES, selected)
256:       end
country_select(object, method, priority_countries = nil, options = {}, html_options = {})

Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 122
122:       def country_select(object, method, priority_countries = nil, options = {}, html_options = {})
123:         InstanceTag.new(object, method, self, nil, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
124:       end
option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)

Returns a string of <option> tags, like options_from_collection_for_select, but groups them by <optgroup> tags based on the object relationships of the arguments.

Parameters:

collection: | An array of objects representing the <optgroup> tags
group_method: | The name of a method which, when called on a member of collection, returns an array of child objects representing the <option> tags
group_label_method: | The name of a method which, when called on a member of collection, returns a string to be used as the label attribute for its <optgroup> tag
option_key_method: | The name of a method which, when called on a child object of a member of collection, returns a value to be used as the value attribute for its <option> tag
option_value_method: | The name of a method which, when called on a child object of a member of collection, returns a value to be used as the contents of its <option> tag
selected_key: | A value equal to the value attribute for one of the <option> tags, which will have the selected attribute set. Corresponds to the return value of one of the calls to option_key_method. If nil, no selection is made.

Example object structure for use with this method:

  class Continent < ActiveRecord::Base
    has_many :countries
    # attribs: id, name
  end
  class Country < ActiveRecord::Base
    belongs_to :continent
    # attribs: id, name, continent_id
  end

Sample usage:

  option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3)

Possible output:

  <optgroup label="Africa">
    <option value="1">Egypt</option>
    <option value="4">Rwanda</option>
    ...
  </optgroup>
  <optgroup label="Asia">
    <option value="3" selected="selected">China</option>
    <option value="12">India</option>
    <option value="5">Japan</option>
    ...
  </optgroup>

Note: Only the <optgroup> and <option> tags are returned, so you still have to wrap the output in an appropriate <select> tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 233
233:       def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
234:         collection.inject("") do |options_for_select, group|
235:           group_label_string = eval("group.#{group_label_method}")
236:           options_for_select += "<optgroup label=\"#{html_escape(group_label_string)}\">"
237:           options_for_select += options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key)
238:           options_for_select += '</optgroup>'
239:         end
240:       end
options_for_select(container, selected = nil)

Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values become lasts. If selected is specified, the matching "last" or element will get the selected option-tag. Selected may also be an array of values to be selected when using a multiple select.

Examples (call, result):

  options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
    <option value="$">Dollar</option>\n<option value="DKK">Kroner</option>

  options_for_select([ "VISA", "MasterCard" ], "MasterCard")
    <option>VISA</option>\n<option selected="selected">MasterCard</option>

  options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
    <option value="$20">Basic</option>\n<option value="$40" selected="selected">Plus</option>

  options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
    <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>

NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 158
158:       def options_for_select(container, selected = nil)
159:         container = container.to_a if Hash === container
160:
161:         options_for_select = container.inject([]) do |options, element|
162:           text, value = option_text_and_value(element)
163:           selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
164:           options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>)
165:         end
166:
167:         options_for_select.join("\n")
168:       end
options_from_collection_for_select(collection, value_method, text_method, selected = nil)

Returns a string of option tags that have been compiled by iterating over the collection and assigning the the result of a call to the value_method as the option value and the text_method as the option text. If selected is specified, the element returning a match on value_method will get the selected option tag.

Example (call, result). Imagine a loop iterating over each person in @project.people to generate an input tag:

  options_from_collection_for_select(@project.people, "id", "name")
    <option value="#{person.id}">#{person.name}</option>

NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 179
179:       def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
180:         options = collection.map do |element|
181:           [element.send(text_method), element.send(value_method)]
182:         end
183:         options_for_select(options, selected)
184:       end
select(object, method, choices, options = {}, html_options = {})

Create a select tag and a series of contained option tags for the provided object and method. The option currently held by the object will be selected, provided that the object is available. See options_for_select for the required format of the choices parameter.

Example with @post.person_id => 1:

  select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => true })

could become:

  <select name="post[person_id]">
    <option value=""></option>
    <option value="1" selected="selected">David</option>
    <option value="2">Sam</option>
    <option value="3">Tobias</option>
  </select>

This can be used to provide a default set of options in the standard way: before rendering the create form, a new model instance is assigned the default options and bound to @model_name. Usually this model is not saved to the database. Instead, a second model object is created when the create request is received. This allows the user to submit a form page more than once with the expected results of creating multiple records. In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.

By default, post.person_id is the selected option. Specify :selected => value to use a different selection or :selected => nil to leave all options unselected.

[ show source ]

    # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 83
83:       def select(object, method, choices, options = {}, html_options = {})
84:         InstanceTag.new(object, method, self, nil, options.delete(:object)).to_select_tag(choices, options, html_options)
85:       end
time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone)

Returns a string of option tags for pretty much any time zone in the world. Supply a TimeZone name as selected to have it marked as the selected option tag. You can also supply an array of TimeZone objects as priority_zones, so that they will be listed above the rest of the (long) list. (You can use TimeZone.us_zones as a convenience for obtaining a list of the US time zones.)

The selected parameter must be either nil, or a string that names a TimeZone.

By default, model is the TimeZone constant (which can be obtained in ActiveRecord as a value object). The only requirement is that the model parameter be an object that responds to all, and returns an array of objects that represent time zones.

NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 275
275:       def time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone)
276:         zone_options = ""
277:
278:         zones = model.all
279:         convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
280:
281:         if priority_zones
282:           zone_options += options_for_select(convert_zones[priority_zones], selected)
283:           zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
284:
285:           zones = zones.reject { |z| priority_zones.include?( z ) }
286:         end
287:
288:         zone_options += options_for_select(convert_zones[zones], selected)
289:         zone_options
290:       end
time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})

Return select and option tags for the given object and method, using time_zone_options_for_select to generate the list of option tags.

In addition to the :include_blank option documented above, this method also supports a :model option, which defaults to TimeZone. This may be used by users to specify a different time zone model object. (See time_zone_options_for_select for more information.)

[ show source ]

     # File actionpack/lib/action_view/helpers/form_options_helper.rb, line 134
134:       def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
135:         InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
136:       end


Module: ActionView::Helpers::FormTagHelper

Module
ActionView::Helpers::FormTagHelper
In: actionpack/lib/action_view/helpers/form_tag_helper.rb

Provides a number of methods for creating form tags that doesn‘t rely on an ActiveRecord object assigned to the template like FormHelper does. Instead, you provide the names and values manually.

NOTE: The HTML options disabled, readonly, and multiple can all be treated as booleans. So specifying :disabled => true will give disabled="disabled".

Methods
  • check_box_tag
  • field_set_tag
  • file_field_tag
  • form_tag
  • hidden_field_tag
  • image_submit_tag
  • password_field_tag
  • radio_button_tag
  • select_tag
  • submit_tag
  • text_area_tag
  • text_field_tag
Public Instance methods
check_box_tag(name, value = "1", checked = false, options = {})

Creates a check box form input tag.

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • Any other key creates standard HTML options for the tag.

Examples

  check_box_tag 'accept'
  # => <input id="accept" name="accept" type="checkbox" value="1" />

  check_box_tag 'rock', 'rock music'
  # => <input id="rock" name="rock" type="checkbox" value="rock music" />

  check_box_tag 'receive_email', 'yes', true
  # => <input checked="checked" id="receive_email" name="receive_email" type="checkbox" value="yes" />

  check_box_tag 'tos', 'yes', false, :class => 'accept_tos'
  # => <input class="accept_tos" id="tos" name="tos" type="checkbox" value="yes" />

  check_box_tag 'eula', 'accepted', false, :disabled => true
  # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 265
265:       def check_box_tag(name, value = "1", checked = false, options = {})
266:         html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
267:         html_options["checked"] = "checked" if checked
268:         tag :input, html_options
269:       end
field_set_tag(legend = nil, &block)

Creates a field set for grouping HTML form elements.

legend will become the fieldset‘s title (optional as per W3C).

Examples

  <% field_set_tag do %>
    <p><%= text_field_tag 'name' %></p>
  <% end %>
  # => <fieldset><p><input id="name" name="name" type="text" /></p></fieldset>

  <% field_set_tag 'Your details' do %>
    <p><%= text_field_tag 'name' %></p>
  <% end %>
  # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset>

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 381
381:       def field_set_tag(legend = nil, &block)
382:         content = capture(&block)
383:         concat(tag(:fieldset, {}, true), block.binding)
384:         concat(content_tag(:legend, legend), block.binding) unless legend.blank?
385:         concat(content, block.binding)
386:         concat("</fieldset>", block.binding)
387:       end
file_field_tag(name, options = {})

Creates a file upload field. If you are using file uploads then you will also need to set the multipart option for the form tag:

  <%= form_tag { :action => "post" }, { :multipart => true } %>
    <label for="file">File to Upload</label> <%= file_field_tag "file" %>
    <%= submit_tag %>
  <%= end_form_tag %>

The specified URL will then be passed a File object containing the selected file, or if the field was left blank, a StringIO object.

Options

  • Creates standard HTML attributes for the tag.
  • :disabled - If set to true, the user will not be able to use this input.

Examples

  file_field_tag 'attachment'
  # => <input id="attachment" name="attachment" type="file" />

  file_field_tag 'avatar', :class => 'profile-input'
  # => <input class="profile-input" id="avatar" name="avatar" type="file" />

  file_field_tag 'picture', :disabled => true
  # => <input disabled="disabled" id="picture" name="picture" type="file" />

  file_field_tag 'resume', :value => '~/resume.doc'
  # => <input id="resume" name="resume" type="file" value="~/resume.doc" />

  file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
  # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />

  file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
  # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 170
170:       def file_field_tag(name, options = {})
171:         text_field_tag(name, nil, options.update("type" => "file"))
172:       end
form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)

Starts a form tag that points the action to an url configured with url_for_options just like ActionController::Base#url_for. The method for the form defaults to POST.

Options

  • :multipart - If set to true, the enctype is set to "multipart/form-data".
  • :method - The method to use when submitting the form, usually either "get" or "post".
                          If "put", "delete", or another verb is used, a hidden input with name _method
                      is added to simulate the verb over post.
  • A list of parameters to feed to the URL the form will be posted to.

Examples

  form_tag('/posts')
  # => <form action="/posts" method="post">

  form_tag('/posts/1', :method => :put)
  # => <form action="/posts/1" method="put">

  form_tag('/upload', :multipart => true)
  # => <form action="/upload" method="post" enctype="multipart/form-data">

  <% form_tag '/posts' do -%>
    <div><%= submit_tag 'Save' %></div>
  <% end -%>
  # => <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form>

[ show source ]

    # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 36
36:       def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
37:         html_options = html_options_for_form(url_for_options, options, *parameters_for_url)
38:         if block_given?
39:           form_tag_in_block(html_options, &block)
40:         else
41:           form_tag_html(html_options)
42:         end
43:       end
hidden_field_tag(name, value = nil, options = {})

Creates a hidden form input field used to transmit data that would be lost due to HTTP‘s statelessness or data that should be hidden from the user.

Options

  • Creates standard HTML attributes for the tag.

Examples

  hidden_field_tag 'tags_list'
  # => <input id="tags_list" name="tags_list" type="hidden" />

  hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
  # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />

  hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
  # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
  #    type="hidden" value="" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 133
133:       def hidden_field_tag(name, value = nil, options = {})
134:         text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
135:       end
image_submit_tag(source, options = {})

Displays an image which when clicked will submit the form.

source is passed to AssetTagHelper#image_path

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • Any other key creates standard HTML options for the tag.

Examples

  image_submit_tag("login.png")
  # => <input src="/images/login.png" type="image" />

  image_submit_tag("purchase.png"), :disabled => true
  # => <input disabled="disabled" src="/images/purchase.png" type="image" />

  image_submit_tag("search.png"), :class => 'search-button'
  # => <input class="search-button" src="/images/search.png" type="image" />

  image_submit_tag("agree.png"), :disabled => true, :class => "agree-disagree-button"
  # => <input class="agree-disagree-button" disabled="disabled" src="/images/agree.png" type="image" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 363
363:       def image_submit_tag(source, options = {})
364:         tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys)
365:       end
password_field_tag(name = "password", value = nil, options = {})

Creates a password field, a masked text field that will hide the users input behind a mask character.

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • :size - The number of visible characters that will fit in the input.
  • :maxlength - The maximum number of characters that the browser will allow the user to enter.
  • Any other key creates standard HTML attributes for the tag.

Examples

  password_field_tag 'pass'
  # => <input id="pass" name="pass" type="password" />

  password_field_tag 'secret', 'Your secret here'
  # => <input id="secret" name="secret" type="password" value="Your secret here" />

  password_field_tag 'masked', nil, :class => 'masked_input_field'
  # => <input class="masked_input_field" id="masked" name="masked" type="password" />

  password_field_tag 'token', '', :size => 15
  # => <input id="token" name="token" size="15" type="password" value="" />

  password_field_tag 'key', nil, :maxlength => 16
  # => <input id="key" maxlength="16" name="key" type="password" />

  password_field_tag 'confirm_pass', nil, :disabled => true
  # => <input disabled="disabled" id="confirm_pass" name="confirm_pass" type="password" />

  password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin-input"
  # => <input class="pin-input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 203
203:       def password_field_tag(name = "password", value = nil, options = {})
204:         text_field_tag(name, value, options.update("type" => "password"))
205:       end
radio_button_tag(name, value, checked = false, options = {})

Creates a radio button; use groups of radio buttons named the same to allow users to select from a group of options.

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • Any other key creates standard HTML options for the tag.

Examples

  radio_button_tag 'gender', 'male'
  # => <input id="gender_male" name="gender" type="radio" value="male" />

  radio_button_tag 'receive_updates', 'no', true
  # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />

  radio_button_tag 'time_slot', "3:00 p.m.", false, :disabled => true
  # => <input disabled="disabled" id="time_slot_300_pm" name="time_slot" type="radio" value="3:00 p.m." />

  radio_button_tag 'color', "green", true, :class => "color_input"
  # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 290
290:       def radio_button_tag(name, value, checked = false, options = {})
291:         pretty_tag_value = value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "").downcase
292:         pretty_name = name.to_s.gsub(/\[/, "_").gsub(/\]/, "")
293:         html_options = { "type" => "radio", "name" => name, "id" => "#{pretty_name}_#{pretty_tag_value}", "value" => value }.update(options.stringify_keys)
294:         html_options["checked"] = "checked" if checked
295:         tag :input, html_options
296:       end
select_tag(name, option_tags = nil, options = {})

Creates a dropdown selection box, or if the :multiple option is set to true, a multiple choice selection box.

Helpers::FormOptions can be used to create common select boxes such as countries, time zones, or associated records. option_tags is a string containing the option tags for the select box.

Options

  • :multiple - If set to true the selection will allow multiple choices.
  • :disabled - If set to true, the user will not be able to use this input.
  • Any other key creates standard HTML attributes for the tag.

Examples

  select_tag "people", "<option>David</option>"
  # => <select id="people" name="people"><option>David</option></select>

  select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>"
  # => <select id="count" name="count"><option>1</option><option>2</option>
  #    <option>3</option><option>4</option></select>

  select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true
  # => <select id="colors" multiple="multiple" name="colors"><option>Red</option>
  #    <option>Green</option><option>Blue</option></select>

  select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>"
  # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option>
  #    <option>Out</option></select>

  select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input'
  # => <select class="form_input" id="access" multiple="multiple" name="access"><option>Read</option>
  #    <option>Write</option></select>

  select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true
  # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
  #    <option>Paris</option><option>Rome</option></select>

[ show source ]

    # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 79
79:       def select_tag(name, option_tags = nil, options = {})
80:         content_tag :select, option_tags, { "name" => name, "id" => name }.update(options.stringify_keys)
81:       end
submit_tag(value = "Save changes", options = {})

Creates a submit button with the text value as the caption.

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • :disable_with - Value of this parameter will be used as the value for a disabled version
                             of the submit button when the form is submitted.
  • Any other key creates standard HTML options for the tag.

Examples

  submit_tag
  # => <input name="commit" type="submit" value="Save changes" />

  submit_tag "Edit this article"
  # => <input name="commit" type="submit" value="Edit this article" />

  submit_tag "Save edits", :disabled => true
  # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />

  submit_tag "Complete sale", :disable_with => "Please wait..."
  # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
  #    type="submit" value="Complete sale" />

  submit_tag nil, :class => "form_submit"
  # => <input class="form_submit" name="commit" type="submit" />

  submit_tag "Edit", :disable_with => "Editing...", :class => 'edit-button'
  # => <input class="edit-button" disable_with="Editing..." name="commit" type="submit" value="Edit" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 325
325:       def submit_tag(value = "Save changes", options = {})
326:         options.stringify_keys!
327:
328:         if disable_with = options.delete("disable_with")
329:           options["onclick"] = [
330:             "this.setAttribute('originalValue', this.value)",
331:             "this.disabled=true",
332:             "this.value='#{disable_with}'",
333:             "#{options["onclick"]}",
334:             "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit())",
335:             "if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false }",
336:             "return result",
337:           ].join(";")
338:         end
339:
340:         tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
341:       end
text_area_tag(name, content = nil, options = {})

Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions.

Options

  • :size - A string specifying the dimensions (columns by rows) of the textarea (e.g., "25x10").
  • :rows - Specify the number of rows in the textarea
  • :cols - Specify the number of columns in the textarea
  • :disabled - If set to true, the user will not be able to use this input.
  • Any other key creates standard HTML attributes for the tag.

Examples

  text_area_tag 'post'
  # => <textarea id="post" name="post"></textarea>

  text_area_tag 'bio', @user.bio
  # => <textarea id="bio" name="bio">This is my biography.</textarea>

  text_area_tag 'body', nil, :rows => 10, :cols => 25
  # => <textarea cols="25" id="body" name="body" rows="10"></textarea>

  text_area_tag 'body', nil, :size => "25x10"
  # => <textarea name="body" id="body" cols="25" rows="10"></textarea>

  text_area_tag 'description', "Description goes here.", :disabled => true
  # => <textarea disabled="disabled" id="description" name="description">Description goes here.</textarea>

  text_area_tag 'comment', nil, :class => 'comment_input'
  # => <textarea class="comment_input" id="comment" name="comment"></textarea>

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 234
234:       def text_area_tag(name, content = nil, options = {})
235:         options.stringify_keys!
236:
237:         if size = options.delete("size")
238:           options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
239:         end
240:
241:         content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys)
242:       end
text_field_tag(name, value = nil, options = {})

Creates a standard text field; use these text fields to input smaller chunks of text like a username or a search query.

Options

  • :disabled - If set to true, the user will not be able to use this input.
  • :size - The number of visible characters that will fit in the input.
  • :maxlength - The maximum number of characters that the browser will allow the user to enter.
  • Any other key creates standard HTML attributes for the tag.

Examples

  text_field_tag 'name'
  # => <input id="name" name="name" type="text" />

  text_field_tag 'query', 'Enter your search query here'
  # => <input id="query" name="query" type="text" value="Enter your search query here" />

  text_field_tag 'request', nil, :class => 'special_input'
  # => <input class="special_input" id="request" name="request" type="text" />

  text_field_tag 'address', '', :size => 75
  # => <input id="address" name="address" size="75" type="text" value="" />

  text_field_tag 'zip', nil, :maxlength => 5
  # => <input id="zip" maxlength="5" name="zip" type="text" />

  text_field_tag 'payment_amount', '$0.00', :disabled => true
  # => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" />

  text_field_tag 'ip', '0.0.0.0', :maxlength => 15, :size => 20, :class => "ip-input"
  # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" />

[ show source ]

     # File actionpack/lib/action_view/helpers/form_tag_helper.rb, line 113
113:       def text_field_tag(name, value = nil, options = {})
114:         tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
115:       end


Module: ActionView::Helpers::JavaScriptHelper

Module
ActionView::Helpers::JavaScriptHelper
In: actionpack/lib/action_view/helpers/javascript_helper.rb

Provides functionality for working with JavaScript in your views.

Ajax, controls and visual effects

  • For information on using Ajax, see ActionView::Helpers::PrototypeHelper.
  • For information on using controls and visual effects, see ActionView::Helpers::ScriptaculousHelper.

Including the JavaScript libraries into your pages

Rails includes the Prototype JavaScript framework and the Scriptaculous JavaScript controls and visual effects library. If you wish to use these libraries and their helpers (ActionView::Helpers::PrototypeHelper and ActionView::Helpers::ScriptaculousHelper), you must do one of the following:

  • Use <%= javascript_include_tag :defaults %> in the HEAD section of your page (recommended): This function will return references to the JavaScript files created by the rails command in your public/javascripts directory. Using it is recommended as the browser can then cache the libraries instead of fetching all the functions anew on every request.
  • Use <%= javascript_include_tag ‘prototype’ %>: As above, but will only include the Prototype core library, which means you are able to use all basic AJAX functionality. For the Scriptaculous-based JavaScript helpers, like visual effects, autocompletion, drag and drop and so on, you should use the method described above.
  • Use <%= define_javascript_functions %>: this will copy all the JavaScript support functions within a single script block. Not recommended.

For documentation on javascript_include_tag see ActionView::Helpers::AssetTagHelper.

Methods
  • array_or_string_for_javascript
  • button_to_function
  • define_javascript_functions
  • escape_javascript
  • javascript_tag
  • link_to_function
  • options_for_javascript
Included Modules
  • PrototypeHelper
Constants
JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts')
Public Instance methods
button_to_function(name, *args, &block)

Returns a button that‘ll trigger a JavaScript function using the onclick handler.

The function argument can be omitted in favor of an update_page block, which evaluates to a string when the template is rendered (instead of making an Ajax request first).

Examples:

  button_to_function "Greeting", "alert('Hello world!')"
  button_to_function "Delete", "if (confirm('Really?')) do_delete()"
  button_to_function "Details" do |page|
    page[:details].visual_effect :toggle_slide
  end
  button_to_function "Details", :class => "details_button" do |page|
    page[:details].visual_effect :toggle_slide
  end

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 113
113:       def button_to_function(name, *args, &block)
114:         html_options = args.extract_options!
115:         function = args[0] || ''
116:
117:         html_options.symbolize_keys!
118:         function = update_page(&block) if block_given?
119:         tag(:input, html_options.merge({
120:           :type => "button", :value => name,
121:           :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
122:         }))
123:       end
define_javascript_functions()

Includes the Action Pack JavaScript libraries inside a single <script> tag. The function first includes prototype.js and then its core extensions, (determined by filenames starting with "prototype"). Afterwards, any additional scripts will be included in undefined order.

Note: The recommended approach is to copy the contents of lib/action_view/helpers/javascripts/ into your application‘s public/javascripts/ directory, and use javascript_include_tag to create remote <script> links.

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 134
134:       def define_javascript_functions
135:         javascript = "<script type=\"#{Mime::JS}\">"
136:
137:         # load prototype.js and its extensions first
138:         prototype_libs = Dir.glob(File.join(JAVASCRIPT_PATH, 'prototype*')).sort.reverse
139:         prototype_libs.each do |filename|
140:           javascript << "\n" << IO.read(filename)
141:         end
142:
143:         # load other libraries
144:         (Dir.glob(File.join(JAVASCRIPT_PATH, '*')) - prototype_libs).each do |filename|
145:           javascript << "\n" << IO.read(filename)
146:         end
147:         javascript << '</script>'
148:       end
escape_javascript(javascript)

Escape carrier returns and single and double quotes for JavaScript segments.

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 151
151:       def escape_javascript(javascript)
152:         (javascript || '').gsub('\\','\0\0').gsub('</','<\/').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
153:       end
javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)

Returns a JavaScript tag with the content inside. Example:

  javascript_tag "alert('All is good')"

Returns:

  <script type="text/javascript">
  //<![CDATA[
  alert('All is good')
  //]]>
  </script>

html_options may be a hash of attributes for the <script> tag. Example:

  javascript_tag "alert('All is good')", :defer => 'defer'
  # => <script defer="defer" type="text/javascript">alert('All is good')</script>

Instead of passing the content as an argument, you can also use a block in which case, you pass your html_options as the first parameter.

  <% javascript_tag :defer => 'defer' do -%>
    alert('All is good')
  <% end -%>

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 174
174:       def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
175:         if block_given?
176:           html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
177:           content = capture(&block)
178:         else
179:           content = content_or_options_with_block
180:         end
181:
182:         javascript_tag = content_tag("script", javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
183:
184:         if block_given? && block_is_within_action_view?(block)
185:           concat(javascript_tag, block.binding)
186:         else
187:           javascript_tag
188:         end
189:       end
link_to_function(name, *args, &block)

Returns a link that will trigger a JavaScript function using the onclick handler and return false after the fact.

The function argument can be omitted in favor of an update_page block, which evaluates to a string when the template is rendered (instead of making an Ajax request first).

Examples:

  link_to_function "Greeting", "alert('Hello world!')"
    Produces:
      <a onclick="alert('Hello world!'); return false;" href="#">Greeting</a>

  link_to_function(image_tag("delete"), "if (confirm('Really?')) do_delete()")
    Produces:
      <a onclick="if (confirm('Really?')) do_delete(); return false;" href="#">
        <img src="/images/delete.png?" alt="Delete"/>
      </a>

  link_to_function("Show me more", nil, :id => "more_link") do |page|
    page[:details].visual_effect  :toggle_blind
    page[:more_link].replace_html "Show me less"
  end
    Produces:
      <a href="#" id="more_link" onclick="try {
        $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
        $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
      }
      catch (e) {
        alert('RJS error:\n\n' + e.toString());
        alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
        \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
        throw e
      };
      return false;">Show me more</a>

[ show source ]

    # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 82
82:       def link_to_function(name, *args, &block)
83:         html_options = args.extract_options!
84:         function = args[0] || ''
85:
86:         html_options.symbolize_keys!
87:         function = update_page(&block) if block_given?
88:         content_tag(
89:           "a", name,
90:           html_options.merge({
91:             :href => html_options[:href] || "#",
92:             :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function}; return false;"
93:           })
94:         )
95:       end
Protected Instance methods
array_or_string_for_javascript(option)

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 200
200:       def array_or_string_for_javascript(option)
201:         js_option = if option.kind_of?(Array)
202:           "['#{option.join('\',\'')}']"
203:         elsif !option.nil?
204:           "'#{option}'"
205:         end
206:         js_option
207:       end
options_for_javascript(options)

[ show source ]

     # File actionpack/lib/action_view/helpers/javascript_helper.rb, line 196
196:       def options_for_javascript(options)
197:         '{' + options.map {|k, v| "#{k}:#{v}"}.sort.join(', ') + '}'
198:       end


Module: ActionView::Helpers::NumberHelper

Module
ActionView::Helpers::NumberHelper
In: actionpack/lib/action_view/helpers/number_helper.rb

Provides methods for converting numbers into formatted strings. Methods are provided for phone numbers, currency, percentage, precision, positional notation, and file size.

Methods
  • number_to_currency
  • number_to_human_size
  • number_to_percentage
  • number_to_phone
  • number_with_delimiter
  • number_with_precision
Public Instance methods
number_to_currency(number, options = {})

Formats a number into a currency string (e.g., $13.65). You can customize the format in the options hash.

Options

  • :precision - Sets the level of precision (defaults to 2).
  • :unit - Sets the denomination of the currency (defaults to "$").
  • :separator - Sets the separator between the units (defaults to ".").
  • :delimiter - Sets the thousands delimiter (defaults to ",").

Examples

 number_to_currency(1234567890.50)                    # => $1,234,567,890.50
 number_to_currency(1234567890.506)                   # => $1,234,567,890.51
 number_to_currency(1234567890.506, :precision => 3)  # => $1,234,567,890.506

 number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
 # => &pound;1234567890,50

[ show source ]

    # File actionpack/lib/action_view/helpers/number_helper.rb, line 65
65:       def number_to_currency(number, options = {})
66:         options   = options.stringify_keys
67:         precision = options["precision"] || 2
68:         unit      = options["unit"] || "$"
69:         separator = precision > 0 ? options["separator"] || "." : ""
70:         delimiter = options["delimiter"] || ","
71:
72:         begin
73:           parts = number_with_precision(number, precision).split('.')
74:           unit + number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s
75:         rescue
76:           number
77:         end
78:       end
number_to_human_size(size, precision=1)

Formats the bytes in size into a more understandable representation (e.g., giving it 1500 yields 1.5 KB). This method is useful for reporting file sizes to users. This method returns nil if size cannot be converted into a number. You can change the default precision of 1 using the precision parameter precision.

Examples

 number_to_human_size(123)           # => 123 Bytes
 number_to_human_size(1234)          # => 1.2 KB
 number_to_human_size(12345)         # => 12.1 KB
 number_to_human_size(1234567)       # => 1.2 MB
 number_to_human_size(1234567890)    # => 1.1 GB
 number_to_human_size(1234567890123) # => 1.1 TB
 number_to_human_size(1234567, 2)    # => 1.18 MB
 number_to_human_size(483989, 0)     # => 4 MB

[ show source ]

     # File actionpack/lib/action_view/helpers/number_helper.rb, line 164
164:       def number_to_human_size(size, precision=1)
165:         size = Kernel.Float(size)
166:         case
167:           when size.to_i == 1;    "1 Byte"
168:           when size < 1.kilobyte; "%d Bytes" % size
169:           when size < 1.megabyte; "%.#{precision}f KB"  % (size / 1.0.kilobyte)
170:           when size < 1.gigabyte; "%.#{precision}f MB"  % (size / 1.0.megabyte)
171:           when size < 1.terabyte; "%.#{precision}f GB"  % (size / 1.0.gigabyte)
172:           else                    "%.#{precision}f TB"  % (size / 1.0.terabyte)
173:         end.sub(/([0-9])\.?0+ /, '\1 ' )
174:       rescue
175:         nil
176:       end
number_to_percentage(number, options = {})

Formats a number as a percentage string (e.g., 65%). You can customize the format in the options hash.

Options

  • :precision - Sets the level of precision (defaults to 3).
  • :separator - Sets the separator between the units (defaults to ".").

Examples

 number_to_percentage(100)                         # => 100.000%
 number_to_percentage(100, :precision => 0)        # => 100%

 number_to_percentage(302.24398923423, :precision => 5)
 # => 302.24399%

[ show source ]

     # File actionpack/lib/action_view/helpers/number_helper.rb, line 93
 93:       def number_to_percentage(number, options = {})
 94:         options   = options.stringify_keys
 95:         precision = options["precision"] || 3
 96:         separator = options["separator"] || "."
 97:
 98:         begin
 99:           number = number_with_precision(number, precision)
100:           parts = number.split('.')
101:           if parts.at(1).nil?
102:             parts[0] + "%"
103:           else
104:             parts[0] + separator + parts[1].to_s + "%"
105:           end
106:         rescue
107:           number
108:         end
109:       end
number_to_phone(number, options = {})

Formats a number into a US phone number (e.g., (555) 123-9876). You can customize the format in the options hash.

Options

  • :area_code - Adds parentheses around the area code.
  • :delimiter - Specifies the delimiter to use (defaults to "-").
  • :extension - Specifies an extension to add to the end of the generated number.
  • :country_code - Sets the country code for the phone number.

Examples

 number_to_phone(1235551234)                                        # => 123-555-1234
 number_to_phone(1235551234, :area_code => true)                    # => (123) 555-1234
 number_to_phone(1235551234, :delimiter => " ")                     # => 123 555 1234
 number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
 number_to_phone(1235551234, :country_code => 1)                    # => +1-123-555-1234

 number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
 => +1.123.555.1234 x 1343

[ show source ]

    # File actionpack/lib/action_view/helpers/number_helper.rb, line 26
26:       def number_to_phone(number, options = {})
27:         number       = number.to_s.strip unless number.nil?
28:         options      = options.stringify_keys
29:         area_code    = options["area_code"] || nil
30:         delimiter    = options["delimiter"] || "-"
31:         extension    = options["extension"].to_s.strip || nil
32:         country_code = options["country_code"] || nil
33:
34:         begin
35:           str = ""
36:           str << "+#{country_code}#{delimiter}" unless country_code.blank?
37:           str << if area_code
38:             number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
39:           else
40:             number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
41:           end
42:           str << " x #{extension}" unless extension.blank?
43:           str
44:         rescue
45:           number
46:         end
47:       end
number_with_delimiter(number, delimiter=",", separator=".")

Formats a number with grouped thousands using delimiter (e.g., 12,324). You can customize the format using optional delimiter and separator parameters.

Options

  • delimiter - Sets the thousands delimiter (defaults to ",").
  • separator - Sets the separator between the units (defaults to ".").

Examples

 number_with_delimiter(12345678)       # => 12,345,678
 number_with_delimiter(12345678.05)    # => 12,345,678.05
 number_with_delimiter(12345678, ".")  # => 12.345.678

 number_with_delimiter(98765432.98, " ", ",")
 # => 98 765 432,98

[ show source ]

     # File actionpack/lib/action_view/helpers/number_helper.rb, line 125
125:       def number_with_delimiter(number, delimiter=",", separator=".")
126:         begin
127:           parts = number.to_s.split('.')
128:           parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
129:           parts.join separator
130:         rescue
131:           number
132:         end
133:       end
number_with_precision(number, precision=3)

Formats a number with the specified level of precision (e.g., 112.32 has a precision of 2). The default level of precision is 3.

Examples

 number_with_precision(111.2345)     # => 111.235
 number_with_precision(111.2345, 2)  # => 111.24
 number_with_precision(13, 5)        # => 13.00000
 number_with_precision(389.32314, 0) # => 389

[ show source ]

     # File actionpack/lib/action_view/helpers/number_helper.rb, line 143
143:       def number_with_precision(number, precision=3)
144:         "%01.#{precision}f" % number
145:       rescue
146:         number
147:       end


Module: ActionView::Helpers::PrototypeHelper

Module
ActionView::Helpers::PrototypeHelper
In: actionpack/lib/action_view/helpers/prototype_helper.rb

Prototype is a JavaScript library that provides DOM manipulation, Ajax functionality, and more traditional object-oriented facilities for JavaScript. This module provides a set of helpers to make it more convenient to call functions from Prototype using Rails, including functionality to call remote Rails methods (that is, making a background request to a Rails action) using Ajax. This means that you can call actions in your controllers without reloading the page, but still update certain parts of it using injections into the DOM. A common use case is having a form that adds a new element to a list without reloading the page or updating a shopping cart total when a new item is added.

Usage

To be able to use these helpers, you must first include the Prototype JavaScript framework in your pages.

 javascript_include_tag 'prototype'

(See the documentation for ActionView::Helpers::JavaScriptHelper for more information on including this and other JavaScript files in your Rails templates.)

Now you‘re ready to call a remote action either through a link…

 link_to_remote "Add to cart",
   :url => { :action => "add", :id => product.id },
   :update => { :success => "cart", :failure => "error" }

…through a form…

 <% form_remote_tag :url => '/shipping' do -%>
   <div><%= submit_tag 'Recalculate Shipping' %></div>
 <% end -%>

…periodically…

 periodically_call_remote(:url => 'update', :frequency => '5', :update => 'ticker')

…or through an observer (i.e., a form or field that is observed and calls a remote action when changed).

 <%= observe_field(:searchbox,
      :url => { :action => :live_search }),
      :frequency => 0.5,
      :update => :hits,
      :with => 'query'
      %>

As you can see, there are numerous ways to use Prototype‘s Ajax functions (and actually more than are listed here); check out the documentation for each method to find out more about its usage and options.

Common Options

See link_to_remote for documentation of options common to all Ajax helpers; any of the options specified by link_to_remote can be used by the other helpers.

Designing your Rails actions for Ajax

When building your action handlers (that is, the Rails actions that receive your background requests), it‘s important to remember a few things. First, whatever your action would normall return to the browser, it will return to the Ajax call. As such, you typically don‘t want to render with a layout. This call will cause the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up. You can turn the layout off on particular actions by doing the following:

 class SiteController < ActionController::Base
   layout "standard", :except => [:ajax_method, :more_ajax, :another_ajax]
 end

Optionally, you could do this in the method you wish to lack a layout:

 render :layout => false

You can tell the type of request from within your action using the request.xhr? (XmlHttpRequest, the method that Ajax uses to make background requests) method.

 def name
   # Is this an XmlHttpRequest request?
   if (request.xhr?)
     render :text => @name.to_s
   else
     # No?  Then render an action.
     render :action => 'view_attribute', :attr => @name
   end
 end

The else clause can be left off and the current action will render with full layout and template. An extension to this solution was posted to Ryan Heneise‘s blog at ArtOfMission.

 layout proc{ |c| c.request.xhr? ? false : "application" }

Dropping this in your ApplicationController turns the layout off for every request that is an "xhr" request.

If you are just returning a little data or don‘t want to build a template for your output, you may opt to simply render text output, like this:

 render :text => 'Return this from my method!'

Since whatever the method returns is injected into the DOM, this will simply inject some text (or HTML, if you tell it to). This is usually how small updates, such updating a cart total or a file count, are handled.

Updating multiple elements

See JavaScriptGenerator for information on updating multiple elements on the page in an Ajax response.

Methods
  • build_callbacks
  • build_observer
  • evaluate_remote_response
  • form_remote_for
  • form_remote_tag
  • link_to_remote
  • method_option_to_s
  • observe_field
  • observe_form
  • options_for_ajax
  • periodically_call_remote
  • remote_form_for
  • remote_function
  • submit_to_remote
  • update_page
  • update_page_tag
Constants
CALLBACKS | = | Set.new([ :uninitialized, :loading, :loaded, :interactive, :complete, :failure, :success ] + (100..599).to_a)
AJAX_OPTIONS | = | Set.new([ :before, :after, :condition, :url, :asynchronous, :method, :insertion, :position, :form, :with, :update, :script ]).merge(CALLBACKS)
Public Instance methods
evaluate_remote_response()

Returns ‘eval(request.responseText)’ which is the JavaScript function that form_remote_tag can call in :complete to evaluate a multiple update return document using update_element_function calls.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 427
427:       def evaluate_remote_response
428:         "eval(request.responseText)"
429:       end
form_remote_for(record_or_name_or_array, *args, &proc)

Alias for remote_form_for

form_remote_tag(options = {}, &block)

Returns a form tag that will submit using XMLHttpRequest in the 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 specifying the target with :url and defining callbacks is the same as link_to_remote.

A "fall-through" target for browsers that doesn‘t do JavaScript can be specified with the :action/:method options on :html.

Example:

  # Generates:
  #      <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
  #      {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
  form_remote_tag :html => { :action =>
    url_for(:controller => "some", :action => "place") }

The Hash passed to the :html key is equivalent to the options (2nd) argument in the FormTagHelper.form_tag method.

By default the fall-through action is the same as the one specified in the :url (and the default method is :post).

form_remote_tag also takes a block, like form_tag:

  # Generates:
  #     <form action="/" method="post" onsubmit="new Ajax.Request('/',
  #     {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
  #     return false;"> <div><input name="commit" type="submit" value="Save" /></div>
  #     </form>
  <% form_remote_tag :url => '/posts' do -%>
    <div><%= submit_tag 'Save' %></div>
  <% end -%>

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 322
322:       def form_remote_tag(options = {}, &block)
323:         options[:form] = true
324:
325:         options[:html] ||= {}
326:         options[:html][:onsubmit] =
327:           (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
328:           "#{remote_function(options)}; return false;"
329:
330:         form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
331:       end
link_to_remote(name, options = {}, html_options = nil)

Returns a link to a remote action defined by options[:url] (using the url_for format) that‘s called in the background using XMLHttpRequest. The result of that request can then be inserted into a DOM object whose id can be specified with options[:update]. Usually, the result would be a partial prepared by the controller with render :partial.

Examples:

  # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
  #            return false;">Delete this post</a>
  link_to_remote "Delete this post", :update => "posts",
    :url => { :action => "destroy", :id => post.id }

  # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
  #            return false;"><img alt="Refresh" src="/images/refresh.png?" /></a>
  link_to_remote(image_tag("refresh"), :update => "emails",
    :url => { :action => "list_emails" })

You can override the generated HTML options by specifying a hash in options[:html].

  link_to_remote "Delete this post", :update => "posts",
    :url  => post_url(@post), :method => :delete,
    :html => { :class  => "destructive" }

You can also specify a hash for options[:update] to allow for easy redirection of output to an other DOM element if a server-side error occurs:

Example:

  # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
  #            {asynchronous:true, evalScripts:true}); return false;">Delete this post</a>
  link_to_remote "Delete this post",
    :url => { :action => "destroy", :id => post.id },
    :update => { :success => "posts", :failure => "error" }

Optionally, you can use the options[:position] parameter to influence how the target DOM element is updated. It must be one of :before, :top, :bottom, or :after.

The method used is by default POST. You can also specify GET or you can simulate PUT or DELETE over POST. All specified with options[:method]

Example:

  # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
  #            return false;">Destroy</a>
  link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete

By default, these remote requests are processed asynchronous during which various JavaScript callbacks can be triggered (for progress indicators and the likes). All callbacks get access to the request object, which holds the underlying XMLHttpRequest.

To access the server response, use request.responseText, to find out the HTTP status, use request.status.

Example:

  # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
  #            onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a>
  word = 'hello'
  link_to_remote word,
    :url => { :action => "undo", :n => word_counter },
    :complete => "undoRequestCompleted(request)"

The callbacks that may be specified are (in order):

:loading: | Called when the remote document is being loaded with data by the browser.
:loaded: | Called when the browser has finished loading the remote document.
:interactive: | Called when the user can interact with the remote document, even though it has not finished loading.
:success: | Called when the XMLHttpRequest is completed, and the HTTP status code is in the 2XX range.
:failure: | Called when the XMLHttpRequest is completed, and the HTTP status code is not in the 2XX range.
:complete: | Called when the XMLHttpRequest is complete (fires after success/failure if they are present).

You can further refine :success and :failure by adding additional callbacks for specific status codes.

Example:

  # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
  #            on404:function(request){alert('Not found...? Wrong URL...?')},
  #            onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
  link_to_remote word,
    :url => { :action => "action" },
    404 => "alert('Not found...? Wrong URL...?')",
    :failure => "alert('HTTP Error ' + request.status + '!')"

A status code callback overrides the success/failure handlers if present.

If you for some reason or another need synchronous processing (that‘ll block the browser while the request is happening), you can specify options[:type] = :synchronous.

You can customize further browser side call logic by passing in JavaScript code snippets via some optional parameters. In their order of use these are:

:confirm: Adds confirmation dialog.
:condition: Perform remote request conditionally by this expression. Use this to describe browser-side conditions when request should not be initiated.
:before: Called before request is initiated.
:after: Called immediately after request was initiated and before :loading.
:submit: Specifies the DOM element ID that‘s used as the parent of the form elements. By default this is the current form, but it could just as well be the ID of a table row or any other DOM element.
:with: A JavaScript expression specifying the parameters for the XMLHttpRequest. Any expressions should return a valid URL query string.

Example:

  :with => "'name=' + $('name').value"

You can generate a link that uses AJAX in the general case, while degrading gracefully to plain link behavior in the absence of JavaScript by setting html_options[:href] to an alternate URL. Note the extra curly braces around the options hash separate it as the second parameter from html_options, the third.

Example:

  link_to_remote "Delete this post",
    { :update => "posts", :url => { :action => "destroy", :id => post.id } },
    :href => url_for(:action => "destroy", :id => post.id)

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 254
254:       def link_to_remote(name, options = {}, html_options = nil)
255:         link_to_function(name, remote_function(options), html_options || options.delete(:html))
256:       end
observe_field(field_id, options = {})

Observes the field with the DOM ID specified by field_id and calls a callback when its contents have changed. The default callback is an Ajax call. By default the value of the observed field is sent as a parameter with the Ajax call.

Example:

 # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
 #         '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})})
 <%= observe_field :suggest, :url => { :action => :find_suggestion },
      :frequency => 0.25,
      :update => :suggest,
      :with => 'q'
      %>

Required options are either of:

:url: url_for-style options for the action to call when the field has changed.
:function: Instead of making a remote call to a URL, you can specify javascript code to be called instead. Note that the value of this option is used as the body of the javascript function, a function definition with parameters named element and value will be generated for you for example:
  observe_field("glass", :frequency => 1, :function => "alert('Element changed')")

will generate:

  new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})

The element parameter is the DOM element being observed, and the value is its value at the time the observer is triggered.

Additional options are:

:frequency: The frequency (in seconds) at which changes to this field will be detected. Not setting this option at all or to a value equal to or less than zero will use event based observation instead of time based observation.
:update: Specifies the DOM ID of the element whose innerHTML should be updated with the XMLHttpRequest response text.
:with: A JavaScript expression specifying the parameters for the XMLHttpRequest. The default is to send the key and value of the observed field. Any custom expressions should return a valid URL query string. The value of the field is stored in the JavaScript variable value.

Examples

  :with => "'my_custom_key=' + value"
  :with => "'person[name]=' + prompt('New name')"
  :with => "Form.Element.serialize('other-field')"

Finally

  :with => 'name'

is shorthand for

  :with => "'name=' + value"

This essentially just changes the key of the parameter.

:on: Specifies which event handler to observe. By default, it‘s set to "changed" for text fields and areas and "click" for radio buttons and checkboxes. With this, you can specify it instead to be "blur" or "focus" or any other event.

Additionally, you may specify any of the options documented in the Common options section at the top of this document.

Example:

  # Sends params: {:title => 'Title of the book'} when the book_title input
  # field is changed.
  observe_field 'book_title',
    :url => 'http://example.com/books/edit/1',
    :with => 'title'

  # Sends params: {:book_title => 'Title of the book'} when the focus leaves
  # the input field.
  observe_field 'book_title',
    :url => 'http://example.com/books/edit/1',
    :on => 'blur'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 551
551:       def observe_field(field_id, options = {})
552:         if options[:frequency] && options[:frequency] > 0
553:           build_observer('Form.Element.Observer', field_id, options)
554:         else
555:           build_observer('Form.Element.EventObserver', field_id, options)
556:         end
557:       end
observe_form(form_id, options = {})

Observes the form with the DOM ID specified by form_id and calls a callback when its contents have changed. The default callback is an Ajax call. By default all fields of the observed field are sent as parameters with the Ajax call.

The options for observe_form are the same as the options for observe_field. The JavaScript variable value available to the :with option is set to the serialized form by default.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 567
567:       def observe_form(form_id, options = {})
568:         if options[:frequency]
569:           build_observer('Form.Observer', form_id, options)
570:         else
571:           build_observer('Form.EventObserver', form_id, options)
572:         end
573:       end
periodically_call_remote(options = {})

Periodically calls the specified url (options[:url]) every options[:frequency] seconds (default is 10). Usually used to update a specified div (options[:update]) with the results of the remote call. The options for specifying the target with :url and defining callbacks is the same as link_to_remote. Examples:

 # Call get_averages and put its results in 'avg' every 10 seconds
 # Generates:
 #      new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages',
 #      {asynchronous:true, evalScripts:true})}, 10)
 periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')

 # Call invoice every 10 seconds with the id of the customer
 # If it succeeds, update the invoice DIV; if it fails, update the error DIV
 # Generates:
 #      new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
 #      '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10)
 periodically_call_remote(:url => { :action => 'invoice', :id => customer.id },
    :update => { :success => "invoice", :failure => "error" }

 # Call update every 20 seconds and update the new_block DIV
 # Generates:
 # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20)
 periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 283
283:       def periodically_call_remote(options = {})
284:          frequency = options[:frequency] || 10 # every ten seconds by default
285:          code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
286:          javascript_tag(code)
287:       end
remote_form_for(record_or_name_or_array, *args, &proc)

Creates a form that will submit using XMLHttpRequest in the background instead of the regular reloading POST arrangement and a scope around a specific resource that is used as a base for questioning about values for the fields.

Resource

Example:

  <% remote_form_for(@post) do |f| %>
    ...
  <% end %>

This will expand to be the same as:

  <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
    ...
  <% end %>

Nested Resource

Example:

  <% remote_form_for([@post, @comment]) do |f| %>
    ...
  <% end %>

This will expand to be the same as:

  <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %>
    ...
  <% end %>

If you don‘t need to attach a form to a resource, then check out form_remote_tag.

See FormHelper#form_for for additional semantics.

This method is also aliased as form_remote_for

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 367
367:       def remote_form_for(record_or_name_or_array, *args, &proc)
368:         options = args.extract_options!
369:
370:         case record_or_name_or_array
371:         when String, Symbol
372:           object_name = record_or_name_or_array
373:         when Array
374:           object = record_or_name_or_array.last
375:           object_name = ActionController::RecordIdentifier.singular_class_name(object)
376:           apply_form_for_options!(record_or_name_or_array, options)
377:           args.unshift object
378:         else
379:           object      = record_or_name_or_array
380:           object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array)
381:           apply_form_for_options!(object, options)
382:           args.unshift object
383:         end
384:
385:         concat(form_remote_tag(options), proc.binding)
386:         fields_for(object_name, *(args << options), &proc)
387:         concat('</form>', proc.binding)
388:       end
remote_function(options)

Returns the JavaScript needed for a remote function. Takes the same arguments as link_to_remote.

Example:

  # Generates: <select id="options" onchange="new Ajax.Updater('options',
  # '/testing/update_options', {asynchronous:true, evalScripts:true})">
  <select id="options" onchange="<%= remote_function(:update => "options",
      :url => { :action => :update_options }) %>">
    <option value="0">Hello</option>
    <option value="1">World</option>
  </select>

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 442
442:       def remote_function(options)
443:         javascript_options = options_for_ajax(options)
444:
445:         update = ''
446:         if options[:update] && options[:update].is_a?(Hash)
447:           update  = []
448:           update << "success:'#{options[:update][:success]}'" if options[:update][:success]
449:           update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
450:           update  = '{' + update.join(',') + '}'
451:         elsif options[:update]
452:           update << "'#{options[:update]}'"
453:         end
454:
455:         function = update.empty? ?
456:           "new Ajax.Request(" :
457:           "new Ajax.Updater(#{update}, "
458:
459:         url_options = options[:url]
460:         url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
461:         function << "'#{url_for(url_options)}'"
462:         function << ", #{javascript_options})"
463:
464:         function = "#{options[:before]}; #{function}" if options[:before]
465:         function = "#{function}; #{options[:after]}"  if options[:after]
466:         function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
467:         function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
468:
469:         return function
470:       end
submit_to_remote(name, value, options = {})

Returns a button input tag with the element name of name and a value (i.e., display text) of value that will submit form using XMLHttpRequest in the background instead of a regular POST request that reloads the page.

 # Create a button that submits to the create action
 #
 # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
 #     {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
 #     return false;" type="button" value="Create" />
 <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>

 # Submit to the remote action update and update the DIV succeed or fail based
 # on the success or failure of the request
 #
 # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
 #      '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
 #      return false;" type="button" value="Update" />
 <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
    :update => { :success => "succeed", :failure => "fail" }

options argument is the same as in form_remote_tag.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 412
412:       def submit_to_remote(name, value, options = {})
413:         options[:with] ||= 'Form.serialize(this.form)'
414:
415:         options[:html] ||= {}
416:         options[:html][:type] = 'button'
417:         options[:html][:onclick] = "#{remote_function(options)}; return false;"
418:         options[:html][:name] = name
419:         options[:html][:value] = value
420:
421:         tag("input", options[:html], false)
422:       end
update_page(&block)

Yields a JavaScriptGenerator and returns the generated JavaScript code. Use this to update multiple elements on a page in an Ajax response. See JavaScriptGenerator for more information.

Example:

  update_page do |page|
    page.hide 'spinner'
  end

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 991
991:       def update_page(&block)
992:         JavaScriptGenerator.new(@template, &block).to_s
993:       end
update_page_tag(html_options = {}, &block)

Works like update_page but wraps the generated JavaScript in a <script> tag. Use this to include generated JavaScript in an ERb template. See JavaScriptGenerator for more information.

html_options may be a hash of <script> attributes to be passed to ActionView::Helpers::JavaScriptHelper#javascript_tag.

[ show source ]

      # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 1001
1001:       def update_page_tag(html_options = {}, &block)
1002:         javascript_tag update_page(&block), html_options
1003:       end
Protected Instance methods
build_callbacks(options)

[ show source ]

      # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 1055
1055:       def build_callbacks(options)
1056:         callbacks = {}
1057:         options.each do |callback, code|
1058:           if CALLBACKS.include?(callback)
1059:             name = 'on' + callback.to_s.capitalize
1060:             callbacks[name] = "function(request){#{code}}"
1061:           end
1062:         end
1063:         callbacks
1064:       end
build_observer(klass, name, options = {})

[ show source ]

      # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 1038
1038:       def build_observer(klass, name, options = {})
1039:         if options[:with] && (options[:with] !~ /[\{=(.]/)
1040:           options[:with] = "'#{options[:with]}=' + value"
1041:         else
1042:           options[:with] ||= 'value' unless options[:function]
1043:         end
1044:
1045:         callback = options[:function] || remote_function(options)
1046:         javascript  = "new #{klass}('#{name}', "
1047:         javascript << "#{options[:frequency]}, " if options[:frequency]
1048:         javascript << "function(element, value) {"
1049:         javascript << "#{callback}}"
1050:         javascript << ", '#{options[:on]}'" if options[:on]
1051:         javascript << ")"
1052:         javascript_tag(javascript)
1053:       end
method_option_to_s(method)

[ show source ]

      # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 1034
1034:       def method_option_to_s(method)
1035:         (method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'"
1036:       end
options_for_ajax(options)

[ show source ]

      # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 1006
1006:       def options_for_ajax(options)
1007:         js_options = build_callbacks(options)
1008:
1009:         js_options['asynchronous'] = options[:type] != :synchronous
1010:         js_options['method']       = method_option_to_s(options[:method]) if options[:method]
1011:         js_options['insertion']    = "Insertion.#{options[:position].to_s.camelize}" if options[:position]
1012:         js_options['evalScripts']  = options[:script].nil? || options[:script]
1013:
1014:         if options[:form]
1015:           js_options['parameters'] = 'Form.serialize(this)'
1016:         elsif options[:submit]
1017:           js_options['parameters'] = "Form.serialize('#{options[:submit]}')"
1018:         elsif options[:with]
1019:           js_options['parameters'] = options[:with]
1020:         end
1021:
1022:         if protect_against_forgery?
1023:           if js_options['parameters']
1024:             js_options['parameters'] << " + '&"
1025:           else
1026:             js_options['parameters'] = "'"
1027:           end
1028:           js_options['parameters'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
1029:         end
1030:
1031:         options_for_javascript(js_options)
1032:       end


Module: ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods

Module
ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods
In: actionpack/lib/action_view/helpers/prototype_helper.rb

JavaScriptGenerator generates blocks of JavaScript code that allow you to change the content and presentation of multiple DOM elements. Use this in your Ajax response bodies, either in a <script> tag or as plain JavaScript sent with a Content-type of "text/javascript".

Create new instances with PrototypeHelper#update_page or with ActionController::Base#render, then call insert_html, replace_html, remove, show, hide, visual_effect, or any other of the built-in methods on the yielded generator in any order you like to modify the content and appearance of the current page.

Example:

  # Generates:
  #     new Insertion.Bottom("list", "<li>Some item</li>");
  #     new Effect.Highlight("list");
  #     ["status-indicator", "cancel-link"].each(Element.hide);
  update_page do |page|
    page.insert_html :bottom, 'list', "<li>#{@item.name}</li>"
    page.visual_effect :highlight, 'list'
    page.hide 'status-indicator', 'cancel-link'
  end

Helper methods can be used in conjunction with JavaScriptGenerator. When a helper method is called inside an update block on the page object, that method will also have access to a page object.

Example:

  module ApplicationHelper
    def update_time
      page.replace_html 'time', Time.now.to_s(:db)
      page.visual_effect :highlight, 'time'
    end
  end

  # Controller action
  def poll
    render(:update) { |page| page.update_time }
  end

You can also use PrototypeHelper#update_page_tag instead of PrototypeHelper#update_page to wrap the generated JavaScript in a <script> tag.

Methods
  • <<
  • []
  • alert
  • assign
  • call
  • delay
  • draggable
  • drop_receiving
  • hide
  • insert_html
  • literal
  • redirect_to
  • remove
  • replace
  • replace_html
  • select
  • show
  • sortable
  • toggle
  • visual_effect
Public Instance methods
<<(javascript)

Writes raw JavaScript to the page.

Example:

 page << "alert('JavaScript with Prototype.');"

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 889
889:           def <<(javascript)
890:             @lines << javascript
891:           end
[](id)

Returns a element reference by finding it through id in the DOM. This element can then be used for further method calls. Examples:

  page['blank_slate']                  # => $('blank_slate');
  page['blank_slate'].show             # => $('blank_slate').show();
  page['blank_slate'].show('first').up # => $('blank_slate').show('first').up();

You can also pass in a record, which will use ActionController::RecordIdentifier.dom_id to lookup the correct id:

  page[@post]     # => $('post_45')
  page[Post.new]  # => $('new_post')

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 660
660:           def [](id)
661:             case id
662:               when String, Symbol, NilClass
663:                 JavaScriptElementProxy.new(self, id)
664:               else
665:                 JavaScriptElementProxy.new(self, ActionController::RecordIdentifier.dom_id(id))
666:             end
667:           end
alert(message)

Displays an alert dialog with the given message.

Example:

  # Generates: alert('This message is from Rails!')
  page.alert('This message is from Rails!')

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 832
832:           def alert(message)
833:             call 'alert', message
834:           end
assign(variable, value)

Assigns the JavaScript variable the given value.

Examples:

 # Generates: my_string = "This is mine!";
 page.assign 'my_string', 'This is mine!'

 # Generates: record_count = 33;
 page.assign 'record_count', 33

 # Generates: tabulated_total = 47
 page.assign 'tabulated_total', @total_from_cart

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 880
880:           def assign(variable, value)
881:             record "#{variable} = #{javascript_object_for(value)}"
882:           end
call(function, *arguments, &block)

Calls the JavaScript function, optionally with the given arguments.

If a block is given, the block will be passed to a new JavaScriptGenerator; the resulting JavaScript code will then be wrapped inside function() { … } and passed as the called function‘s final argument.

Examples:

 # Generates: Element.replace(my_element, "My content to replace with.")
 page.call 'Element.replace', 'my_element', "My content to replace with."

 # Generates: alert('My message!')
 page.call 'alert', 'My message!'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 863
863:           def call(function, *arguments, &block)
864:             record "#{function}(#{arguments_for_call(arguments, block)})"
865:           end
delay(seconds = 1) {|| ...}

Executes the content of the block after a delay of seconds. Example:

  # Generates:
  #     setTimeout(function() {
  #     ;
  #     new Effect.Fade("notice",{});
  #     }, 20000);
  page.delay(20) do
    page.visual_effect :fade, 'notice'
  end

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 903
903:           def delay(seconds = 1)
904:             record "setTimeout(function() {\n\n"
905:             yield
906:             record "}, #{(seconds * 1000).to_i})"
907:           end
draggable(id, options = {})

Creates a script.aculo.us draggable element. See ActionView::Helpers::ScriptaculousHelper for more information.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 925
925:           def draggable(id, options = {})
926:             record @context.send(:draggable_element_js, id, options)
927:           end
drop_receiving(id, options = {})

Creates a script.aculo.us drop receiving element. See ActionView::Helpers::ScriptaculousHelper for more information.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 931
931:           def drop_receiving(id, options = {})
932:             record @context.send(:drop_receiving_element_js, id, options)
933:           end
hide(*ids)

Hides the visible DOM elements with the given ids.

Example:

 # Hide a few people
 # Generates: ["person_29", "person_9", "person_0"].each(Element.hide);
 page.hide 'person_29', 'person_9', 'person_0'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 810
810:           def hide(*ids)
811:             loop_on_multiple_args 'Element.hide', ids
812:           end
insert_html(position, id, *options_for_render)

Inserts HTML at the specified position relative to the DOM element identified by the given id.

position may be one of:

:top: | HTML is inserted inside the element, before the element‘s existing content.
:bottom: | HTML is inserted inside the element, after the element‘s existing content.
:before: | HTML is inserted immediately preceding the element.
:after: | HTML is inserted immediately following the element.

options_for_render may be either a string of HTML to insert, or a hash of options to be passed to ActionView::Base#render. For example:

  # Insert the rendered 'navigation' partial just before the DOM
  # element with ID 'content'.
  # Generates: new Insertion.Before("content", "-- Contents of 'navigation' partial --");
  insert_html :before, 'content', :partial => 'navigation'

  # Add a list item to the bottom of the <ul> with ID 'list'.
  # Generates: new Insertion.Bottom("list", "<li>Last item</li>");
  insert_html :bottom, 'list', '<li>Last item</li>'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 725
725:           def insert_html(position, id, *options_for_render)
726:             insertion = position.to_s.camelize
727:             call "new Insertion.#{insertion}", id, render(*options_for_render)
728:           end
literal(code)

Returns an object whose to_json evaluates to code. Use this to pass a literal JavaScript expression as an argument to another JavaScriptGenerator method.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 671
671:           def literal(code)
672:             ActiveSupport::JSON::Variable.new(code.to_s)
673:           end
redirect_to(location)

Redirects the browser to the given location using JavaScript, in the same form as url_for.

Examples:

 # Generates: window.location.href = "/mycontroller";
 page.redirect_to(:action => 'index')

 # Generates: window.location.href = "/account/signup";
 page.redirect_to(:controller => 'account', :action => 'signup')

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 845
845:           def redirect_to(location)
846:             assign 'window.location.href', @context.url_for(location)
847:           end
remove(*ids)

Removes the DOM elements with the given ids from the page.

Example:

 # Remove a few people
 # Generates: ["person_23", "person_9", "person_2"].each(Element.remove);
 page.remove 'person_23', 'person_9', 'person_2'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 786
786:           def remove(*ids)
787:             loop_on_multiple_args 'Element.remove', ids
788:           end
replace(id, *options_for_render)

Replaces the "outer HTML" (i.e., the entire element, not just its contents) of the DOM element with the given id.

options_for_render may be either a string of HTML to insert, or a hash of options to be passed to ActionView::Base#render. For example:

  # Replace the DOM element having ID 'person-45' with the
  # 'person' partial for the appropriate object.
  replace 'person-45', :partial => 'person', :object => @person

This allows the same partial that is used for the insert_html to be also used for the input to replace without resorting to the use of wrapper elements.

Examples:

  <div id="people">
    <%= render :partial => 'person', :collection => @people %>
  </div>

  # Insert a new person
  #
  # Generates: new Insertion.Bottom({object: "Matz", partial: "person"}, "");
  page.insert_html :bottom, :partial => 'person', :object => @person

  # Replace an existing person

  # Generates: Element.replace("person_45", "-- Contents of partial --");
  page.replace 'person_45', :partial => 'person', :object => @person

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 774
774:           def replace(id, *options_for_render)
775:             call 'Element.replace', id, render(*options_for_render)
776:           end
replace_html(id, *options_for_render)

Replaces the inner HTML of the DOM element with the given id.

options_for_render may be either a string of HTML to insert, or a hash of options to be passed to ActionView::Base#render. For example:

  # Replace the HTML of the DOM element having ID 'person-45' with the
  # 'person' partial for the appropriate object.
  # Generates:  Element.update("person-45", "-- Contents of 'person' partial --");
  replace_html 'person-45', :partial => 'person', :object => @person

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 740
740:           def replace_html(id, *options_for_render)
741:             call 'Element.update', id, render(*options_for_render)
742:           end
select(pattern)

Returns a collection reference by finding it through a CSS pattern in the DOM. This collection can then be used for further method calls. Examples:

  page.select('p')                      # => $$('p');
  page.select('p.welcome b').first      # => $$('p.welcome b').first();
  page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide();

You can also use prototype enumerations with the collection. Observe:

  # Generates: $$('#items li').each(function(value) { value.hide(); });
  page.select('#items li').each do |value|
    value.hide
  end

Though you can call the block param anything you want, they are always rendered in the javascript as ‘value, index.’ Other enumerations, like collect() return the last statement:

  # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); });
  page.select('#items li').collect('hidden') do |item|
    item.hide
  end

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 697
697:           def select(pattern)
698:             JavaScriptElementCollectionProxy.new(self, pattern)
699:           end
show(*ids)

Shows hidden DOM elements with the given ids.

Example:

 # Show a few people
 # Generates: ["person_6", "person_13", "person_223"].each(Element.show);
 page.show 'person_6', 'person_13', 'person_223'

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 798
798:           def show(*ids)
799:             loop_on_multiple_args 'Element.show', ids
800:           end
sortable(id, options = {})

Creates a script.aculo.us sortable element. Useful to recreate sortable elements after items get added or deleted. See ActionView::Helpers::ScriptaculousHelper for more information.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 919
919:           def sortable(id, options = {})
920:             record @context.send(:sortable_element_js, id, options)
921:           end
toggle(*ids)

Toggles the visibility of the DOM elements with the given ids. Example:

 # Show a few people
 # Generates: ["person_14", "person_12", "person_23"].each(Element.toggle);
 page.toggle 'person_14', 'person_12', 'person_23'      # Hides the elements
 page.toggle 'person_14', 'person_12', 'person_23'      # Shows the previously hidden elements

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 822
822:           def toggle(*ids)
823:             loop_on_multiple_args 'Element.toggle', ids
824:           end
visual_effect(name, id = nil, options = {})

Starts a script.aculo.us visual effect. See ActionView::Helpers::ScriptaculousHelper for more information.

[ show source ]

     # File actionpack/lib/action_view/helpers/prototype_helper.rb, line 911
911:           def visual_effect(name, id = nil, options = {})
912:             record @context.send(:visual_effect, name, id, options)
913:           end


Module: ActionView::Helpers::RecordIdentificationHelper

Module
ActionView::Helpers::RecordIdentificationHelper
In: actionpack/lib/action_view/helpers/record_identification_helper.rb
Methods
  • dom_class
  • dom_id
  • partial_path
Public Instance methods
dom_class(*args, &block)

See ActionController::RecordIdentifier.dom_class — this is just a delegate to that for convenient access in the view.

[ show source ]

    # File actionpack/lib/action_view/helpers/record_identification_helper.rb, line 10
10:       def dom_class(*args, &block)
11:         ActionController::RecordIdentifier.dom_class(*args, &block)
12:       end
dom_id(*args, &block)

See ActionController::RecordIdentifier.dom_id — this is just a delegate to that for convenient access in the view.

[ show source ]

    # File actionpack/lib/action_view/helpers/record_identification_helper.rb, line 15
15:       def dom_id(*args, &block)
16:         ActionController::RecordIdentifier.dom_id(*args, &block)
17:       end
partial_path(*args, &block)

See ActionController::RecordIdentifier.partial_path — this is just a delegate to that for convenient access in the view.

[ show source ]

   # File actionpack/lib/action_view/helpers/record_identification_helper.rb, line 5
5:       def partial_path(*args, &block)
6:         ActionController::RecordIdentifier.partial_path(*args, &block)
7:       end


Module: ActionView::Helpers::RecordTagHelper

Module
ActionView::Helpers::RecordTagHelper
In: actionpack/lib/action_view/helpers/record_tag_helper.rb
Methods
  • content_tag_for
  • div_for
Public Instance methods
content_tag_for(tag_name, record, *args, &block)

content_tag_for creates an HTML element with id and class parameters that relate to the specified ActiveRecord object. For example:

   <% content_tag_for(:tr, @person) do %>
     <td><%=h @person.first_name %></td>
     <td><%=h @person.last_name %></td>
   <% end %>

would produce hthe following HTML (assuming @person is an instance of a Person object, with an id value of 123):

   <tr id="person_123" class="person">....</tr>

If you require the HTML id attribute to have a prefix, you can specify it:

   <% content_tag_for(:tr, @person, :foo) do %> ...

produces:

   <tr id="foo_person_123" class="person">...

content_tag_for also accepts a hash of options, which will be converted to additional HTML attributes. If you specify a :class value, it will be combined with the default class name for your object. For example:

   <% content_tag_for(:li, @person, :class => "bar") %>...

produces:

   <li id="person_123" class="person bar">...

[ show source ]

    # File actionpack/lib/action_view/helpers/record_tag_helper.rb, line 50
50:       def content_tag_for(tag_name, record, *args, &block)
51:         prefix  = args.first.is_a?(Hash) ? nil : args.shift
52:         options = args.first.is_a?(Hash) ? args.shift : {}
53:         concat content_tag(tag_name, capture(&block),
54:           options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })),
55:           block.binding
56:       end
div_for(record, *args, &block)

Produces a wrapper DIV element with id and class parameters that relate to the specified ActiveRecord object. Usage example:

   <% div_for(@person, :class => "foo") do %>
      <%=h @person.name %>
   <% end %>

produces:

   <div id="person_123" class="person foo"> Joe Bloggs </div>

[ show source ]

    # File actionpack/lib/action_view/helpers/record_tag_helper.rb, line 15
15:       def div_for(record, *args, &block)
16:         content_tag_for(:div, record, *args, &block)
17:       end


Module: ActionView::Helpers::SanitizeHelper

Module
ActionView::Helpers::SanitizeHelper
In: actionpack/lib/action_view/helpers/sanitize_helper.rb

The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements. These helper methods extend ActionView making them callable within your template files.

Methods
  • included
  • sanitize
  • sanitize_css
  • strip_links
  • strip_tags
Public Class methods
included(base)

[ show source ]

    # File actionpack/lib/action_view/helpers/sanitize_helper.rb, line 9
 9:       def self.included(base)
10:         base.extend(ClassMethods)
11:       end
Public Instance methods
sanitize(html, options = {})

This sanitize helper will html encode all tags and strip all attributes that aren‘t specifically allowed. It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out the extensive test suite.

  <%= sanitize @article.body %>

You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the available options. You can add tags/attributes for single uses of sanitize by passing either the :attributes or :tags options:

Normal Use

  <%= sanitize @article.body %>

Custom Use (only the mentioned tags and attributes are allowed, nothing else)

  <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)

Add table tags to the default allowed tags

  Rails::Initializer.run do |config|
    config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
  end

Remove tags to the default allowed tags

  Rails::Initializer.run do |config|
    config.after_initialize do
      ActionView::Base.sanitized_allowed_tags.delete 'div'
    end
  end

Change allowed default attributes

  Rails::Initializer.run do |config|
    config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
  end

[ show source ]

    # File actionpack/lib/action_view/helpers/sanitize_helper.rb, line 51
51:       def sanitize(html, options = {})
52:         self.class.white_list_sanitizer.sanitize(html, options)
53:       end
sanitize_css(style)

Sanitizes a block of css code. Used by sanitize when it comes across a style attribute

[ show source ]

    # File actionpack/lib/action_view/helpers/sanitize_helper.rb, line 56
56:       def sanitize_css(style)
57:         self.class.white_list_sanitizer.sanitize_css(style)
58:       end
strip_links(html)

Strips all link tags from text leaving just the link text.

Examples

  strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>')
  # => Ruby on Rails

  strip_links('Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.')
  # => Please e-mail me at me@email.com.

  strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.')
  # => Blog: Visit

[ show source ]

    # File actionpack/lib/action_view/helpers/sanitize_helper.rb, line 89
89:       def strip_links(html)
90:         self.class.link_sanitizer.sanitize(html)
91:       end
strip_tags(html)

Strips all HTML tags from the html, including comments. This uses the html-scanner tokenizer and so its HTML parsing ability is limited by that of html-scanner.

Examples

  strip_tags("Strip <i>these</i> tags!")
  # => Strip these tags!

  strip_tags("<b>Bold</b> no more!  <a href='more.html'>See more here</a>...")
  # => Bold no more!  See more here...

  strip_tags("<div id='top-bar'>Welcome to my website!</div>")
  # => Welcome to my website!

[ show source ]

    # File actionpack/lib/action_view/helpers/sanitize_helper.rb, line 74
74:       def strip_tags(html)
75:         self.class.full_sanitizer.sanitize(html)
76:       end


Module: ActionView::Helpers::ScriptaculousHelper

Module
ActionView::Helpers::ScriptaculousHelper
In: actionpack/lib/action_view/helpers/scriptaculous_helper.rb

Provides a set of helpers for calling Scriptaculous JavaScript functions, including those which create Ajax controls and visual effects.

To be able to use these helpers, you must include the Prototype JavaScript framework and the Scriptaculous JavaScript library in your pages. See the documentation for ActionView::Helpers::JavaScriptHelper for more information on including the necessary JavaScript.

The Scriptaculous helpers’ behavior can be tweaked with various options. See the documentation at script.aculo.us for more information on using these helpers in your application.

Methods
  • draggable_element
  • drop_receiving_element
  • sortable_element
  • visual_effect
Constants
TOGGLE_EFFECTS = [:toggle_appear, :toggle_slide, :toggle_blind]
Public Instance methods
draggable_element(element_id, options = {})

Makes the element with the DOM ID specified by element_id draggable.

Example:

  <%= draggable_element("my_image", :revert => true)

You can change the behaviour with various options, see script.aculo.us for more documentation.

[ show source ]

     # File actionpack/lib/action_view/helpers/scriptaculous_helper.rb, line 164
164:       def draggable_element(element_id, options = {})
165:         javascript_tag(draggable_element_js(element_id, options).chop!)
166:       end
drop_receiving_element(element_id, options = {})

Makes the element with the DOM ID specified by element_id receive dropped draggable elements (created by draggable_element). and make an AJAX call By default, the action called gets the DOM ID of the element as parameter.

Example:

  <%= drop_receiving_element("my_cart", :url =>
    { :controller => "cart", :action => "add" }) %>

You can change the behaviour with various options, see script.aculo.us for more documentation.

[ show source ]

     # File actionpack/lib/action_view/helpers/scriptaculous_helper.rb, line 183
183:       def drop_receiving_element(element_id, options = {})
184:         javascript_tag(drop_receiving_element_js(element_id, options).chop!)
185:       end
sortable_element(element_id, options = {})

Makes the element with the DOM ID specified by element_id sortable by drag-and-drop and make an Ajax call whenever the sort order has changed. By default, the action called gets the serialized sortable element as parameters.

Example:

  <%= sortable_element("my_list", :url => { :action => "order" }) %>

In the example, the action gets a "my_list" array parameter containing the values of the ids of elements the sortable consists of, in the current order.

Important: For this to work, the sortable elements must have id attributes in the form "string_identifier". For example, "item_1". Only the identifier part of the id attribute will be serialized.

Additional options are:

:format: | A regular expression to determine what to send as the serialized id to the server (the default is /^[^_]*_(.*)$/).
:constraint: | Whether to constrain the dragging to either :horizontal or :vertical (or false to make it unconstrained).
:overlap: | Calculate the item overlap in the :horizontal or :vertical direction.
:tag: | Which children of the container element to treat as sortable (default is li).
:containment: | Takes an element or array of elements to treat as potential drop targets (defaults to the original target element).
:only: | A CSS class name or arry of class names used to filter out child elements as candidates.
:scroll: | Determines whether to scroll the list during drag operationsif the list runs past the visual border.
:tree: | Determines whether to treat nested lists as part of the main sortable list. This means that you can create multi- layer lists, and not only sort items at the same level, but drag and sort items between levels.
:hoverclass: | If set, the Droppable will have this additional CSS class when an accepted Draggable is hovered over it.
:handle: | Sets whether the element should only be draggable by an embedded handle. The value may be a string referencing a CSS class value (as of script.aculo.us V1.5). The first child/grandchild/etc. element found within the element that has this CSS class value will be used as the handle.
:ghosting: | Clones the element and drags the clone, leaving the original in place until the clone is dropped (defaut is false).
:dropOnEmpty: | If set to true, the Sortable container will be made into a Droppable, that can receive a Draggable (as according to the containment rules) as a child element when there are no more elements inside (defaut is false).
:onChange: | Called whenever the sort order changes while dragging. When dragging from one Sortable to another, the callback is called once on each Sortable. Gets the affected element as its parameter.
:onUpdate: | Called when the drag ends and the Sortable‘s order is changed in any way. When dragging from one Sortable to another, the callback is called once on each Sortable. Gets the container as its parameter.

See script.aculo.us for more documentation.

[ show source ]

     # File actionpack/lib/action_view/helpers/scriptaculous_helper.rb, line 138
138:       def sortable_element(element_id, options = {})
139:         javascript_tag(sortable_element_js(element_id, options).chop!)
140:       end
visual_effect(name, element_id = false, js_options = {})

Returns a JavaScript snippet to be used on the Ajax callbacks for starting visual effects.

Example:

  <%= link_to_remote "Reload", :update => "posts",
        :url => { :action => "reload" },
        :complete => visual_effect(:highlight, "posts", :duration => 0.5)

If no element_id is given, it assumes "element" which should be a local variable in the generated JavaScript execution context. This can be used for example with drop_receiving_element:

  <%= drop_receiving_element (...), :loading => visual_effect(:fade) %>

This would fade the element that was dropped on the drop receiving element.

For toggling visual effects, you can use :toggle_appear, :toggle_slide, and :toggle_blind which will alternate between appear/fade, slidedown/slideup, and blinddown/blindup respectively.

You can change the behaviour with various options, see script.aculo.us for more documentation.

[ show source ]

    # File actionpack/lib/action_view/helpers/scriptaculous_helper.rb, line 44
44:       def visual_effect(name, element_id = false, js_options = {})
45:         element = element_id ? element_id.to_json : "element"
46:
47:         js_options[:queue] = if js_options[:queue].is_a?(Hash)
48:           '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
49:         elsif js_options[:queue]
50:           "'#{js_options[:queue]}'"
51:         end if js_options[:queue]
52:
53:         [:endcolor, :direction, :startcolor, :scaleMode, :restorecolor].each do |option|
54:           js_options[option] = "'#{js_options[option]}'" if js_options[option]
55:         end
56:
57:         if TOGGLE_EFFECTS.include? name.to_sym
58:           "Effect.toggle(#{element},'#{name.to_s.gsub(/^toggle_/,'')}',#{options_for_javascript(js_options)});"
59:         else
60:           "new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
61:         end
62:       end


Module: ActionView::Helpers::TagHelper

Module
ActionView::Helpers::TagHelper
In: actionpack/lib/action_view/helpers/tag_helper.rb

Provides methods to generate HTML tags programmatically when you can‘t use a Builder. By default, they output XHTML compliant tags.

Methods
  • cdata_section
  • content_tag
  • escape_once
  • tag
Included Modules
  • ERB::Util
Constants
BOOLEAN_ATTRIBUTES = Set.new(%w(disabled readonly multiple))
Public Instance methods
cdata_section(content)

Returns a CDATA section with the given content. CDATA sections are used to escape blocks of text containing characters which would otherwise be recognized as markup. CDATA sections begin with the string <![CDATA[ and end with (and may not contain) the string ]]>.

Examples

  cdata_section("<hello world>")
  # => <![CDATA[<hello world>]]>

  cdata_section(File.read("hello_world.txt"))
  # => <![CDATA[<hello from a text file]]>

[ show source ]

    # File actionpack/lib/action_view/helpers/tag_helper.rb, line 89
89:       def cdata_section(content)
90:         "<![CDATA[#{content}]]>"
91:       end
content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)

Returns an HTML block tag of type name surrounding the content. Add HTML attributes by passing an attributes hash to options. Instead of passing the content as an argument, you can also use a block in which case, you pass your options as the second parameter. Set escape to false to disable attribute value escaping.

Options

The options hash is used with attributes with no value like (disabled and readonly), which you can give a value of true in the options hash. You can use symbols or strings for the attribute names.

Examples

  content_tag(:p, "Hello world!")
   # => <p>Hello world!</p>
  content_tag(:div, content_tag(:p, "Hello world!"), :class => "strong")
   # => <div class="strong"><p>Hello world!</p></div>
  content_tag("select", options, :multiple => true)
   # => <select multiple="multiple">...options...</select>

  <% content_tag :div, :class => "strong" do -%>
    Hello world!
  <% end -%>
   # => <div class="strong"><p>Hello world!</p></div>

[ show source ]

    # File actionpack/lib/action_view/helpers/tag_helper.rb, line 66
66:       def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
67:         if block_given?
68:           options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
69:           content = capture(&block)
70:           content_tag = content_tag_string(name, content, options, escape)
71:           block_is_within_action_view?(block) ? concat(content_tag, block.binding) : content_tag
72:         else
73:           content = content_or_options_with_block
74:           content_tag_string(name, content, options, escape)
75:         end
76:       end
escape_once(html)

Returns an escaped version of html without affecting existing escaped entities.

Examples

  escape_once("1 > 2 &amp; 3")
  # => "1 &lt; 2 &amp; 3"

  escape_once("&lt;&lt; Accept & Checkout")
  # => "&lt;&lt; Accept &amp; Checkout"

[ show source ]

     # File actionpack/lib/action_view/helpers/tag_helper.rb, line 101
101:       def escape_once(html)
102:         html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
103:       end
tag(name, options = nil, open = false, escape = true)

Returns an empty HTML tag of type name which by default is XHTML compliant. Set open to true to create an open tag compatible with HTML 4.0 and below. Add HTML attributes by passing an attributes hash to options. Set escape to false to disable attribute value escaping.

Options

The options hash is used with attributes with no value like (disabled and readonly), which you can give a value of true in the options hash. You can use symbols or strings for the attribute names.

Examples

  tag("br")
  # => <br />

  tag("br", nil, true)
  # => <br>

  tag("input", { :type => 'text', :disabled => true })
  # => <input type="text" disabled="disabled" />

  tag("img", { :src => "open & shut.png" })
  # => <img src="open &amp; shut.png" />

  tag("img", { :src => "open &amp; shut.png" }, false, false)
  # => <img src="open &amp; shut.png" />

[ show source ]

    # File actionpack/lib/action_view/helpers/tag_helper.rb, line 39
39:       def tag(name, options = nil, open = false, escape = true)
40:         "<#{name}#{tag_options(options, escape) if options}" + (open ? ">" : " />")
41:       end


Module: ActionView::Helpers::TextHelper

Module
ActionView::Helpers::TextHelper
In: actionpack/lib/action_view/helpers/text_helper.rb

The TextHelper module provides a set of methods for filtering, formatting and transforming strings, which can reduce the amount of inline Ruby code in your views. These helper methods extend ActionView making them callable within your template files.

Methods
  • auto_link
  • concat
  • cycle
  • excerpt
  • highlight
  • markdown
  • pluralize
  • reset_cycle
  • simple_format
  • textilize
  • textilize_without_paragraph
  • truncate
  • word_wrap
Constants
AUTO_LINK_RE = %r{ ( # leading text <\w+.*?>| # leading HTML tag, or [^=!:'"/]| # leading punctuation, or ^ # beginning of line ) ( (?:https?://)| # protocol spec, or (?:www\.) # www.* ) ( [-\w]+ # subdomain or domain (?:\.[-\w]+)* # remaining subdomains or domain (?::\d+)? # port (?:/(?:(?:[~\w\+@%-]|(?:[,.;:][^\s$]))+)?)* # path (?:\?[\w\+@%&=.;-]+)? # query string (?:\#[\w\-]*)? # trailing anchor ) ([[:punct:]]|\s|<|$) # trailing text }x unless const_defined?(:AUTO_LINK_RE)
Public Instance methods
auto_link(text, link = :all, href_options = {}, &block)

Turns all URLs and e-mail addresses into clickable links. The link parameter will limit what should be linked. You can add HTML attributes to the links using href_options. Options for link are :all (default), :email_addresses, and :urls. If a block is given, each URL and e-mail address is yielded and the result is used as the link text.

Examples

  auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
  # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
  #     say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"

  auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :urls)
  # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
  #     or e-mail david@loudthinking.com"

  auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :email_addresses)
  # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"

  post_body = "Welcome to my new blog at http://www.myblog.com/.  Please e-mail me at me@email.com."
  auto_link(post_body, :all, :target => '_blank') do |text|
    truncate(text, 15)
  end
  # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
        Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 307
307:       def auto_link(text, link = :all, href_options = {}, &block)
308:         return '' if text.blank?
309:         case link
310:           when :all             then auto_link_email_addresses(auto_link_urls(text, href_options, &block), &block)
311:           when :email_addresses then auto_link_email_addresses(text, &block)
312:           when :urls            then auto_link_urls(text, href_options, &block)
313:         end
314:       end
concat(string, binding)

The preferred method of outputting text in your views is to use the <%= "text" %> eRuby syntax. The regular puts and print methods do not operate as expected in an eRuby code block. If you absolutely must output text within a non-output code block (i.e., <% %>), you can use the concat method.

Examples

  <%
      concat "hello", binding
      # is the equivalent of <%= "hello" %>

      if (logged_in == true):
        concat "Logged in!", binding
      else
        concat link_to('login', :action => login), binding
      end
      # will either display "Logged in!" or a login link
  %>

[ show source ]

    # File actionpack/lib/action_view/helpers/text_helper.rb, line 28
28:       def concat(string, binding)
29:         eval(ActionView::Base.erb_variable, binding) << string
30:       end
cycle(first_value, *values)

Creates a Cycle object whose to_s method cycles through elements of an array every time it is called. This can be used for example, to alternate classes for table rows. You can use named cycles to allow nesting in loops. Passing a Hash as the last parameter with a :name key will create a named cycle. You can manually reset a cycle by calling reset_cycle and passing the name of the cycle.

Examples

  # Alternate CSS classes for even and odd numbers...
  @items = [1,2,3,4]
  <table>
  <% @items.each do |item| %>
    <tr class="<%= cycle("even", "odd") -%>">
      <td>item</td>
    </tr>
  <% end %>
  </table>

  # Cycle CSS classes for rows, and text colors for values within each row
  @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
               {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
              {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
  <% @items.each do |item| %>
    <tr class="<%= cycle("even", "odd", :name => "row_class") -%>">
      <td>
        <% item.values.each do |value| %>
          <%# Create a named cycle "colors" %>
          <span style="color:<%= cycle("red", "green", "blue", :name => "colors") -%>">
            <%= value %>
          </span>
        <% end %>
        <% reset_cycle("colors") %>
      </td>
   </tr>
 <% end %>

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 352
352:       def cycle(first_value, *values)
353:         if (values.last.instance_of? Hash)
354:           params = values.pop
355:           name = params[:name]
356:         else
357:           name = "default"
358:         end
359:         values.unshift(first_value)
360:
361:         cycle = get_cycle(name)
362:         if (cycle.nil? || cycle.values != values)
363:           cycle = set_cycle(name, Cycle.new(*values))
364:         end
365:         return cycle.to_s
366:       end
excerpt(text, phrase, radius = 100, excerpt_string = "...")

Extracts an excerpt from text that matches the first instance of phrase. The radius expands the excerpt on each side of the first occurrence of phrase by the number of characters defined in radius (which defaults to 100). If the excerpt radius overflows the beginning or end of the text, then the excerpt_string will be prepended/appended accordingly. If the phrase isn‘t found, nil is returned.

Examples

  excerpt('This is an example', 'an', 5)
  # => "...s is an examp..."

  excerpt('This is an example', 'is', 5)
  # => "This is an..."

  excerpt('This is an example', 'is')
  # => "This is an example"

  excerpt('This next thing is an example', 'ex', 2)
  # => "...next t..."

  excerpt('This is also an example', 'an', 8, '<chop> ')
  # => "<chop> is also an example"

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 101
101:       def excerpt(text, phrase, radius = 100, excerpt_string = "...")
102:         if text.nil? || phrase.nil? then return end
103:         phrase = Regexp.escape(phrase)
104:
105:         if found_pos = text.chars =~ /(#{phrase})/i
106:           start_pos = [ found_pos - radius, 0 ].max
107:           end_pos   = [ found_pos + phrase.chars.length + radius, text.chars.length ].min
108:
109:           prefix  = start_pos > 0 ? excerpt_string : ""
110:           postfix = end_pos < text.chars.length ? excerpt_string : ""
111:
112:           prefix + text.chars[start_pos..end_pos].strip + postfix
113:         else
114:           nil
115:         end
116:       end
highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>')

Highlights one or more phrases everywhere in text by inserting it into a highlighter string. The highlighter can be specialized by passing highlighter as a single-quoted string with \1 where the phrase is to be inserted (defaults to ’<strong class="highlight">\1</strong>’)

Examples

  highlight('You searched for: rails', 'rails')
  # => You searched for: <strong class="highlight">rails</strong>

  highlight('You searched for: ruby, rails, dhh', 'actionpack')
  # => You searched for: ruby, rails, dhh

  highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
  # => You searched <em>for</em>: <em>rails</em>

  highlight('You searched for: rails', 'rails', "<a href='search?q=\1'>\1</a>")
  # => You searched for: <a href='search?q=rails>rails</a>

[ show source ]

    # File actionpack/lib/action_view/helpers/text_helper.rb, line 71
71:       def highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>')
72:         if text.blank? || phrases.blank?
73:           text
74:         else
75:           match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
76:           text.gsub(/(#{match})/i, highlighter)
77:         end
78:       end
markdown(text)

Returns the text with all the Markdown codes turned into HTML tags. This method is only available if BlueCloth is available.

Examples

  markdown("We are using __Markdown__ now!")
  # => "<p>We are using <strong>Markdown</strong> now!</p>"

  markdown("We like to _write_ `code`, not just _read_ it!")
  # => "<p>We like to <em>write</em> <code>code</code>, not just <em>read</em> it!</p>"

  markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
  # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
  #     has more information.</p>"

  markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
  # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 249
249:         def markdown(text)
250:           text.blank? ? "" : BlueCloth.new(text).to_html
251:         end
pluralize(count, singular, plural = nil)

Attempts to pluralize the singular word unless count is 1. If plural is supplied, it will use that when count is > 1, if the ActiveSupport Inflector is loaded, it will use the Inflector to determine the plural form, otherwise it will just add an ‘s’ to the singular word.

Examples

  pluralize(1, 'person')
  # => 1 person

  pluralize(2, 'person')
  # => 2 people

  pluralize(3, 'person', 'users')
  # => 3 users

  pluralize(0, 'person')
  # => 0 people

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 135
135:       def pluralize(count, singular, plural = nil)
136:          "#{count || 0} " + if count == 1 || count == '1'
137:           singular
138:         elsif plural
139:           plural
140:         elsif Object.const_defined?("Inflector")
141:           Inflector.pluralize(singular)
142:         else
143:           singular + "s"
144:         end
145:       end
reset_cycle(name = "default")

Resets a cycle so that it starts from the first element the next time it is called. Pass in name to reset a named cycle.

Example

  # Alternate CSS classes for even and odd numbers...
  @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
  <table>
  <% @items.each do |item| %>
    <tr class="<%= cycle("even", "odd") -%>">
        <% item.each do |value| %>
          <span style="color:<%= cycle("#333", "#666", "#999", :name => "colors") -%>">
            <%= value %>
          </span>
        <% end %>

        <% reset_cycle("colors") %>
    </tr>
  <% end %>
  </table>

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 387
387:       def reset_cycle(name = "default")
388:         cycle = get_cycle(name)
389:         cycle.reset unless cycle.nil?
390:       end
simple_format(text)

Returns text transformed into HTML using simple formatting rules. Two or more consecutive newlines(\n\n) are considered as a paragraph and wrapped in <p> tags. One newline (\n) is considered as a linebreak and a <br /> tag is appended. This method does not remove the newlines from the text.

Examples

  my_text = """Here is some basic text...
            ...with a line break."""

  simple_format(my_text)
  # => "<p>Here is some basic text...<br />...with a line break.</p>"

  more_text = """We want to put a paragraph...

              ...right there."""

  simple_format(more_text)
  # => "<p>We want to put a paragraph...</p><p>...right there.</p>"

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 275
275:       def simple_format(text)
276:         content_tag 'p', text.to_s.
277:           gsub(/\r\n?/, "\n").                    # \r\n and \r -> \n
278:           gsub(/\n\n+/, "</p>\n\n<p>").           # 2+ newline  -> paragraph
279:           gsub(/([^\n]\n)(?=[^\n])/, '\1<br />')  # 1 newline   -> br
280:       end
textilize(text)

Returns the text with all the Textile codes turned into HTML tags.

You can learn more about Textile‘s syntax at its website. This method is only available if RedCloth is available.

Examples

  textilize("*This is Textile!*  Rejoice!")
  # => "<p><strong>This is Textile!</strong>  Rejoice!</p>"

  textilize("I _love_ ROR(Ruby on Rails)!")
  # => "<p>I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!</p>"

  textilize("h2. Textile makes markup -easy- simple!")
  # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"

  textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
  # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>"

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 190
190:         def textilize(text)
191:           if text.blank?
192:             ""
193:           else
194:             textilized = RedCloth.new(text, [ :hard_breaks ])
195:             textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
196:             textilized.to_html
197:           end
198:         end
textilize_without_paragraph(text)

Returns the text with all the Textile codes turned into HTML tags, but without the bounding <p> tag that RedCloth adds.

You can learn more about Textile‘s syntax at its website. This method is only available if RedCloth is available.

Examples

  textilize_without_paragraph("*This is Textile!*  Rejoice!")
  # => "<strong>This is Textile!</strong>  Rejoice!"

  textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
  # => "I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!"

  textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
  # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"

  textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
  # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 219
219:         def textilize_without_paragraph(text)
220:           textiled = textilize(text)
221:           if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
222:           if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
223:           return textiled
224:         end
truncate(text, length = 30, truncate_string = "...")

If text is longer than length, text will be truncated to the length of length (defaults to 30) and the last characters will be replaced with the truncate_string (defaults to "…").

Examples

  truncate("Once upon a time in a world far far away", 14)
  # => Once upon a...

  truncate("Once upon a time in a world far far away")
  # => Once upon a time in a world f...

  truncate("And they found that many people were sleeping better.", 25, "(clipped)")
  # => And they found that many (clipped)

  truncate("And they found that many people were sleeping better.", 15, "... (continued)")
  # => And they found... (continued)

[ show source ]

    # File actionpack/lib/action_view/helpers/text_helper.rb, line 48
48:       def truncate(text, length = 30, truncate_string = "...")
49:         if text.nil? then return end
50:         l = length - truncate_string.chars.length
51:         (text.chars.length > length ? text.chars[0...l] + truncate_string : text).to_s
52:       end
word_wrap(text, line_width = 80)

Wraps the text into lines no longer than line_width width. This method breaks on the first whitespace character that does not exceed line_width (which is 80 by default).

Examples

  word_wrap('Once upon a time', 4)
  # => Once\nupon\na\ntime

  word_wrap('Once upon a time', 8)
  # => Once upon\na time

  word_wrap('Once upon a time')
  # => Once upon a time

  word_wrap('Once upon a time', 1)
  # => Once\nupon\na\ntime

[ show source ]

     # File actionpack/lib/action_view/helpers/text_helper.rb, line 163
163:       def word_wrap(text, line_width = 80)
164:         text.split("\n").collect do |line|
165:           line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
166:         end * "\n"
167:       end


Module: ActionView::Helpers::UrlHelper

Module
ActionView::Helpers::UrlHelper
In: actionpack/lib/action_view/helpers/url_helper.rb

Provides a set of methods for making links and getting URLs that depend on the routing subsystem (see ActionController::Routing). This allows you to use the same format for links in views and controllers.

Methods
  • button_to
  • current_page?
  • link_to
  • link_to_if
  • link_to_unless
  • link_to_unless_current
  • mail_to
  • url_for
Included Modules
  • JavaScriptHelper
Public Instance methods
button_to(name, options = {}, html_options = {})

Generates a form containing a single button that submits to the URL created by the set of options. This is the safest method to ensure links that cause changes to your data are not triggered by search bots or accelerators. If the HTML button does not work with your layout, you can also consider using the link_to method with the :method modifier as described in the link_to documentation.

The generated FORM element has a class name of button-to to allow styling of the form itself and its children. You can control the form submission and input element behavior using html_options. This method accepts the :method and :confirm modifiers described in the link_to documentation. If no :method modifier is given, it will default to performing a POST operation. You can also disable the button by passing :disabled => true in html_options. If you are using RESTful routes, you can pass the :method to change the HTTP verb used to submit the form.

Options

The options hash accepts the same options at url_for.

There are a few special html_options:

  • :method — specifies the anchor name to be appended to the path.
  • :disabled — specifies the anchor name to be appended to the path.
  • :confirm — This will add a JavaScript confirm prompt with the question specified. If the user accepts, the link is processed normally, otherwise no action is taken.

Examples

  <%= button_to "New", :action => "new" %>
  # => "<form method="post" action="/controller/new" class="button-to">
  #      <div><input value="New" type="submit" /></div>
  #    </form>"

  button_to "Delete Image", { :action => "delete", :id => @image.id },
            :confirm => "Are you sure?", :method => :delete
  # => "<form method="post" action="/images/delete/1" class="button-to">
  #      <div>
  #        <input type="hidden" name="_method" value="delete" />
  #        <input onclick="return confirm('Are you sure?');"
  #              value="Delete" type="submit" />
  #      </div>
  #    </form>"

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 202
202:       def button_to(name, options = {}, html_options = {})
203:         html_options = html_options.stringify_keys
204:         convert_boolean_attributes!(html_options, %w( disabled ))
205:
206:         method_tag = ''
207:         if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
208:           method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
209:         end
210:
211:         form_method = method.to_s == 'get' ? 'get' : 'post'
212:
213:         request_token_tag = ''
214:         if form_method == 'post' && protect_against_forgery?
215:           request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
216:         end
217:
218:         if confirm = html_options.delete("confirm")
219:           html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
220:         end
221:
222:         url = options.is_a?(String) ? options : self.url_for(options)
223:         name ||= url
224:
225:         html_options.merge!("type" => "submit", "value" => name)
226:
227:         "<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
228:           method_tag + tag("input", html_options) + request_token_tag + "</div></form>"
229:       end
current_page?(options)

True if the current request URI was generated by the given options.

Examples

Let‘s say we‘re in the /shop/checkout action.

  current_page?(:action => 'process')
  # => false

  current_page?(:controller => 'shop', :action => 'checkout')
  # => true

  current_page?(:action => 'checkout')
  # => true

  current_page?(:controller => 'library', :action => 'checkout')
  # => false

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 435
435:       def current_page?(options)
436:         url_string = CGI.escapeHTML(url_for(options))
437:         request = @controller.request
438:         if url_string =~ /^\w+:\/\//
439:           url_string == "#{request.protocol}#{request.host_with_port}#{request.request_uri}"
440:         else
441:           url_string == request.request_uri
442:         end
443:       end
link_to(name, options = {}, html_options = nil)

Creates a link tag of the given name using a URL created by the set of options. See the valid options in the documentation for url_for. It‘s also possible to pass a string instead of an options hash to get a link tag that uses the value of the string as the href for the link, or use +:back+ to link to the referrer - a JavaScript back link will be used in place of a referrer if none exists. If nil is passed as a name, the link itself will become the name.

Options

  • :confirm => ‘question?‘ — This will add a JavaScript confirm prompt with the question specified. If the user accepts, the link is processed normally, otherwise no action is taken.
  • :popup => true || array of window options — This will force the link to open in a popup window. By passing true, a default browser window will be opened with the URL. You can also specify an array of options that are passed-thru to JavaScripts window.open method.
  • :method => symbol of HTTP verb — This modifier will dynamically create an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform a POST operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are :post, :delete and :put. Note that if the user has JavaScript disabled, the request will fall back to using GET. If you are relying on the POST behavior, you should check for it in your controller‘s action by using the request object‘s methods for post?, delete? or put?.
  • The html_options will accept a hash of html attributes for the link tag.

Note that if the user has JavaScript disabled, the request will fall back to using GET. If :href=>’#’ is used and the user has JavaScript disabled clicking the link will have no effect. If you are relying on the POST behavior, your should check for it in your controller‘s action by using the request object‘s methods for post?, delete? or put?.

You can mix and match the html_options with the exception of :popup and :method which will raise an ActionView::ActionViewError exception.

Examples

  link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?"
  # => <a href="http://www.rubyonrails.org/" onclick="return confirm('Are you sure?');">Visit Other Site</a>

  link_to "Help", { :action => "help" }, :popup => true
  # => <a href="/testing/help/" onclick="window.open(this.href);return false;">Help</a>

  link_to "View Image", { :action => "view" }, :popup => ['new_window_name', 'height=300,width=600']
  # => <a href="/testing/view/" onclick="window.open(this.href,'new_window_name','height=300,width=600');return false;">View Image</a>

  link_to "Delete Image", { :action => "delete", :id => @image.id }, :confirm => "Are you sure?", :method => :delete
  # => <a href="/testing/delete/9/" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form');
       f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
       var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
       m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 137
137:       def link_to(name, options = {}, html_options = nil)
138:         url = case options
139:           when String
140:             options
141:           when :back
142:             @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
143:           else
144:             self.url_for(options)
145:           end
146:
147:         if html_options
148:           html_options = html_options.stringify_keys
149:           href = html_options['href']
150:           convert_options_to_javascript!(html_options, url)
151:           tag_options = tag_options(html_options)
152:         else
153:           tag_options = nil
154:         end
155:
156:         href_attr = "href=\"#{url}\"" unless href
157:         "<a #{href_attr}#{tag_options}>#{name || url}</a>"
158:       end
link_to_if(condition, name, options = {}, html_options = {}, &block)

Creates a link tag of the given name using a URL created by the set of options if condition is true, in which case only the name is returned. To specialize the default behavior, you can pass a block that accepts the name or the full argument list for link_to_unless (see the examples in link_to_unless).

Examples

  <%= link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) %>
  # If the user isn't logged in...
  # => <a href="/sessions/new/">Login</a>

  <%=
     link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) do
       link_to(@current_user.login, { :controller => "accounts", :action => "show", :id => @current_user })
     end
  %>
  # If the user isn't logged in...
  # => <a href="/sessions/new/">Login</a>
  # If they are logged in...
  # => <a href="/accounts/show/3">my_username</a>

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 326
326:       def link_to_if(condition, name, options = {}, html_options = {}, &block)
327:         link_to_unless !condition, name, options, html_options, &block
328:       end
link_to_unless(condition, name, options = {}, html_options = {}) {|name| ...}

Creates a link tag of the given name using a URL created by the set of options unless condition is true, in which case only the name is returned. To specialize the default behavior (i.e., show a login link rather than just the plaintext link text), you can pass a block that accepts the name or the full argument list for link_to_unless.

Examples

  <%= link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) %>
  # If the user is logged in...
  # => <a href="/controller/reply/">Reply</a>

  <%=
     link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) do |name|
       link_to(name, { :controller => "accounts", :action => "signup" })
     end
  %>
  # If the user is logged in...
  # => <a href="/controller/reply/">Reply</a>
  # If not...
  # => <a href="/accounts/signup">Reply</a>

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 294
294:       def link_to_unless(condition, name, options = {}, html_options = {}, &block)
295:         if condition
296:           if block_given?
297:             block.arity <= 1 ? yield(name) : yield(name, options, html_options)
298:           else
299:             name
300:           end
301:         else
302:           link_to(name, options, html_options)
303:         end
304:       end
link_to_unless_current(name, options = {}, html_options = {}, &block)

Creates a link tag of the given name using a URL created by the set of options unless the current request URI is the same as the links, in which case only the name is returned (or the given block is yielded, if one exists). You can give link_to_unless_current a block which will specialize the default behavior (e.g., show a "Start Here" link rather than the link‘s text).

Examples

Let‘s say you have a navigation menu…

  <ul id="navbar">
    <li><%= link_to_unless_current("Home", { :action => "index" }) %></li>
    <li><%= link_to_unless_current("About Us", { :action => "about" }) %></li>
  </ul>

If in the "about" action, it will render…

  <ul id="navbar">
    <li><a href="/controller/index">Home</a></li>
    <li>About Us</li>
  </ul>

…but if in the "home" action, it will render:

  <ul id="navbar">
    <li><a href="/controller/index">Home</a></li>
    <li><a href="/controller/about">About Us</a></li>
  </ul>

The implicit block given to link_to_unless_current is evaluated if the current action is the action given. So, if we had a comments page and wanted to render a "Go Back" link instead of a link to the comments page, we could do something like this…

   <%=
       link_to_unless_current("Comment", { :controller => 'comments', :action => 'new}) do
          link_to("Go back", { :controller => 'posts', :action => 'index' })
       end
    %>

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 270
270:       def link_to_unless_current(name, options = {}, html_options = {}, &block)
271:         link_to_unless current_page?(options), name, options, html_options, &block
272:       end
mail_to(email_address, name = nil, html_options = {})

Creates a mailto link tag to the specified email_address, which is also used as the name of the link unless name is specified. Additional HTML attributes for the link can be passed in html_options.

mail_to has several methods for hindering email harvesters and customizing the email itself by passing special keys to html_options.

Options

  • :encode - This key will accept the strings "javascript" or "hex". Passing "javascript" will dynamically create and encode the mailto: link then eval it into the DOM of the page. This method will not show the link on the page if the user has JavaScript disabled. Passing "hex" will hex encode the email_address before outputting the mailto: link.
  • :replace_at - When the link name isn‘t provided, the email_address is used for the link label. You can use this option to obfuscate the email_address by substituting the @ sign with the string given as the value.
  • :replace_dot - When the link name isn‘t provided, the email_address is used for the link label. You can use this option to obfuscate the email_address by substituting the . in the email with the string given as the value.
  • :subject - Preset the subject line of the email.
  • :body - Preset the body of the email.
  • :cc - Carbon Copy addition recipients on the email.
  • :bcc - Blind Carbon Copy additional recipients on the email.

Examples

  mail_to "me@domain.com"
  # => <a href="mailto:me@domain.com">me@domain.com</a>

  mail_to "me@domain.com", "My email", :encode => "javascript"
  # => <script type="text/javascript">eval(unescape('%64%6f%63...%6d%65%6e'))</script>

  mail_to "me@domain.com", "My email", :encode => "hex"
  # => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>

  mail_to "me@domain.com", nil, :replace_at => "_at_", :replace_dot => "_dot_", :class => "email"
  # => <a href="mailto:me@domain.com" class="email">me_at_domain_dot_com</a>

  mail_to "me@domain.com", "My email", :cc => "ccaddress@domain.com",
           :subject => "This is an example email"
  # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>

[ show source ]

     # File actionpack/lib/action_view/helpers/url_helper.rb, line 372
372:       def mail_to(email_address, name = nil, html_options = {})
373:         html_options = html_options.stringify_keys
374:         encode = html_options.delete("encode").to_s
375:         cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
376:
377:         string = ''
378:         extras = ''
379:         extras << "cc=#{CGI.escape(cc).gsub("+", "%20")}&" unless cc.nil?
380:         extras << "bcc=#{CGI.escape(bcc).gsub("+", "%20")}&" unless bcc.nil?
381:         extras << "body=#{CGI.escape(body).gsub("+", "%20")}&" unless body.nil?
382:         extras << "subject=#{CGI.escape(subject).gsub("+", "%20")}&" unless subject.nil?
383:         extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
384:
385:         email_address = email_address.to_s
386:
387:         email_address_obfuscated = email_address.dup
388:         email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
389:         email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
390:
391:         if encode == "javascript"
392:           tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');"
393:           for i in 0...tmp.length
394:             string << sprintf("%%%x",tmp[i])
395:           end
396:           "<script type=\"#{Mime::JS}\">eval(unescape('#{string}'))</script>"
397:         elsif encode == "hex"
398:           email_address_encoded = ''
399:           email_address_obfuscated.each_byte do |c|
400:             email_address_encoded << sprintf("&#%d;", c)
401:           end
402:
403:           protocol = 'mailto:'
404:           protocol.each_byte { |c| string << sprintf("&#%d;", c) }
405:
406:           for i in 0...email_address.length
407:             if email_address[i,1] =~ /\w/
408:               string << sprintf("%%%x",email_address[i])
409:             else
410:               string << email_address[i,1]
411:             end
412:           end
413:           content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
414:         else
415:           content_tag "a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
416:         end
417:       end
url_for(options = {})

Returns the URL for the set of options provided. This takes the same options as url_for in ActionController (see the documentation for ActionController::Base#url_for). Note that by default :only_path is true so you‘ll get the relative /controller/action instead of the fully qualified URL like example.com/controller/action.

When called from a view, url_for returns an HTML escaped url. If you need an unescaped url, pass :escape => false in the options.

Options

  • :anchor — specifies the anchor name to be appended to the path.
  • :only_path — if true, returns the relative URL (omitting the protocol, host name, and port) (true by default unless :host is specified)
  • :trailing_slash — if true, adds a trailing slash, as in "/archive/2005/". Note that this is currently not recommended since it breaks caching.
  • :host — overrides the default (current) host if provided
  • :protocol — overrides the default (current) protocol if provided
  • :user — Inline HTTP authentication (only plucked out if :password is also present)
  • :password — Inline HTTP authentication (only plucked out if :user is also present)
  • :escape — Determines whether the returned URL will be HTML escaped or not (true by default)

Relying on named routes

If you instead of a hash pass a record (like an Active Record or Active Resource) as the options parameter, you‘ll trigger the named route for that record. The lookup will happen on the name of the class. So passing a Workshop object will attempt to use the workshop_path route. If you have a nested route, such as admin_workshop_path you‘ll have to call that explicitly (it‘s impossible for url_for to guess that route).

Examples

  <%= url_for(:action => 'index') %>
  # => /blog/

  <%= url_for(:action => 'find', :controller => 'books') %>
  # => /books/find

  <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %>
  # => https://www.railsapplication.com/members/login/

  <%= url_for(:action => 'play', :anchor => 'player') %>
  # => /messages/play/#player

  <%= url_for(:action => 'checkout', :anchor => 'tax&ship') %>
  # => /testing/jump/#tax&amp;ship

  <%= url_for(:action => 'checkout', :anchor => 'tax&ship', :escape => false) %>
  # => /testing/jump/#tax&ship

  <%= url_for(Workshop.new) %>
  # relies on Workshop answering a new_record? call (and in this case returning true)
  # => /workshops

  <%= url_for(@workshop) %>
  # calls @workshop.to_s
  # => /workshops/5

[ show source ]

    # File actionpack/lib/action_view/helpers/url_helper.rb, line 65
65:       def url_for(options = {})
66:         case options
67:         when Hash
68:           show_path =  options[:host].nil? ? true : false
69:           options = { :only_path => show_path }.update(options.symbolize_keys)
70:           escape  = options.key?(:escape) ? options.delete(:escape) : true
71:           url     = @controller.send(:url_for, options)
72:         when String
73:           escape = true
74:           url    = options
75:         when NilClass
76:           url = @controller.send(:url_for, nil)
77:         else
78:           escape = false
79:           url    = polymorphic_path(options)
80:         end
81:
82:         escape ? escape_once(url) : url
83:       end


Module: ActionView::Partials

Module
ActionView::Partials
In: actionpack/lib/action_view/partials.rb

There‘s also a convenience method for rendering sub templates within the current controller that depends on a single object (we call this kind of sub templates for partials). It relies on the fact that partials should follow the naming convention of being prefixed with an underscore — as to separate them from regular templates that could be rendered on their own.

In a template for Advertiser#account:

 <%= render :partial => "account" %>

This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable account to the template for display.

In another template for Advertiser#buy, we could have:

  <%= render :partial => "account", :locals => { :account => @buyer } %>

  <% for ad in @advertisements %>
    <%= render :partial => "ad", :locals => { :ad => ad } %>
  <% end %>

This would first render "advertiser/_account.erb" with @buyer passed in as the local variable account, then render "advertiser/_ad.erb" and pass the local variable ad to the template for display.

Rendering a collection of partials

The example of partial use describes a familiar pattern where a template needs to iterate over an array and render a sub template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders a partial by the same name as the elements contained within. So the three-lined example in "Using partials" can be rewritten with a single line:

  <%= render :partial => "ad", :collection => @advertisements %>

This will render "advertiser/_ad.erb" and pass the local variable ad to the template for display. An iteration counter will automatically be made available to the template with a name of the form partial_name_counter. In the case of the example above, the template would be fed ad_counter.

NOTE: Due to backwards compatibility concerns, the collection can‘t be one of hashes. Normally you‘d also just keep domain objects, like Active Records, in there.

Rendering shared partials

Two controllers can share a set of partials and render them like this:

  <%= render :partial => "advertisement/ad", :locals => { :ad => @advertisement } %>

This will render the partial "advertisement/_ad.erb" regardless of which controller this is being called from.

Rendering partials with layouts

Partials can have their own layouts applied to them. These layouts are different than the ones that are specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types of users:

  <%# app/views/users/index.html.erb &>
  Here's the administrator:
  <%= render :partial => "user", :layout => "administrator", :locals => { :user => administrator } %>

  Here's the editor:
  <%= render :partial => "user", :layout => "editor", :locals => { :user => editor } %>

  <%# app/views/users/_user.html.erb &>
  Name: <%= user.name %>

  <%# app/views/users/_administrator.html.erb &>
  <div id="administrator">
    Budget: $<%= user.budget %>
    <%= yield %>
  </div>

  <%# app/views/users/_editor.html.erb &>
  <div id="editor">
    Deadline: $<%= user.deadline %>
    <%= yield %>
  </div>

…this will return:

  Here's the administrator:
  <div id="administrator">
    Budget: $<%= user.budget %>
    Name: <%= user.name %>
  </div>

  Here's the editor:
  <div id="editor">
    Deadline: $<%= user.deadline %>
    Name: <%= user.name %>
  </div>

You can also apply a layout to a block within any template:

  <%# app/views/users/_chief.html.erb &>
  <% render(:layout => "administrator", :locals => { :user => chief }) do %>
    Title: <%= chief.title %>
  <% end %>

…this will return:

  <div id="administrator">
    Budget: $<%= user.budget %>
    Title: <%= chief.name %>
  </div>

As you can see, the :locals hash is shared between both the partial and its layout.


Class: ActionView::TemplateHandler

Class
ActionView::TemplateHandler
In: | actionpack/lib/action_view/template_handler.rb
Parent: | Object
Methods
  • compile
  • line_offset
  • new
  • render
Public Class methods
line_offset()

[ show source ]

   # File actionpack/lib/action_view/template_handler.rb, line 3
3:     def self.line_offset
4:       0
5:     end
new(view)

[ show source ]

   # File actionpack/lib/action_view/template_handler.rb, line 7
7:     def initialize(view)
8:       @view = view
9:     end
Public Instance methods
compile(template)

[ show source ]

    # File actionpack/lib/action_view/template_handler.rb, line 14
14:     def compile(template)
15:     end
render(template, local_assigns)

[ show source ]

    # File actionpack/lib/action_view/template_handler.rb, line 11
11:     def render(template, local_assigns)
12:     end


Module: ActionView::TemplateHandlers

Module
ActionView::TemplateHandlers
In: actionpack/lib/action_view/template_handlers/builder.rb actionpack/lib/action_view/template_handlers/erb.rb actionpack/lib/action_view/template_handlers/rjs.rb
Classes and Modules
Class ActionView::TemplateHandlers::Builder
Class ActionView::TemplateHandlers::ERB
Class ActionView::TemplateHandlers::RJS


Class: ActionView::TemplateHandlers::Builder

Class
ActionView::TemplateHandlers::Builder
In: | actionpack/lib/action_view/template_handlers/builder.rb
Parent: | TemplateHandler
Methods
  • compile
  • line_offset
Public Class methods
line_offset()

[ show source ]

   # File actionpack/lib/action_view/template_handlers/builder.rb, line 6
6:       def self.line_offset
7:         2
8:       end
Public Instance methods
compile(template)

[ show source ]

    # File actionpack/lib/action_view/template_handlers/builder.rb, line 10
10:       def compile(template)
11:         content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller")
12:         "#{content_type_handler}.content_type ||= Mime::XML\n" +
13:         "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
14:         template +
15:         "\nxml.target!\n"
16:       end


Class: ActionView::TemplateHandlers::ERB

Class
ActionView::TemplateHandlers::ERB
In: | actionpack/lib/action_view/template_handlers/erb.rb
Parent: | TemplateHandler
Methods
  • compile
Public Instance methods
compile(template)

[ show source ]

    # File actionpack/lib/action_view/template_handlers/erb.rb, line 16
16:       def compile(template)
17:         ::ERB.new(template, nil, @view.erb_trim_mode).src
18:       end


Class: ActionView::TemplateHandlers::RJS

Class
ActionView::TemplateHandlers::RJS
In: | actionpack/lib/action_view/template_handlers/rjs.rb
Parent: | TemplateHandler
Methods
  • compile
  • line_offset
Public Class methods
line_offset()

[ show source ]

   # File actionpack/lib/action_view/template_handlers/rjs.rb, line 4
4:       def self.line_offset
5:         2
6:       end
Public Instance methods
compile(template)

[ show source ]

    # File actionpack/lib/action_view/template_handlers/rjs.rb, line 8
 8:       def compile(template)
 9:         "controller.response.content_type ||= Mime::JS\n" +
10:         "update_page do |page|\n#{template}\nend"
11:       end


File: base.rb

File
base.rb
Path: | actionpack/lib/action_view/base.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: compiled_templates.rb

File
compiled_templates.rb
Path: | actionpack/lib/action_view/compiled_templates.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: active_record_helper.rb

File
active_record_helper.rb
Path: | actionpack/lib/action_view/helpers/active_record_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • action_view/helpers/form_helper


File: asset_tag_helper.rb

File
asset_tag_helper.rb
Path: | actionpack/lib/action_view/helpers/asset_tag_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • action_view/helpers/url_helper
  • action_view/helpers/tag_helper


File: atom_feed_helper.rb

File
atom_feed_helper.rb
Path: | actionpack/lib/action_view/helpers/atom_feed_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERb or any other template languages).


File: benchmark_helper.rb

File
benchmark_helper.rb
Path: | actionpack/lib/action_view/helpers/benchmark_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • benchmark


File: cache_helper.rb

File
cache_helper.rb
Path: | actionpack/lib/action_view/helpers/cache_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: capture_helper.rb

File
capture_helper.rb
Path: | actionpack/lib/action_view/helpers/capture_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: date_helper.rb

File
date_helper.rb
Path: | actionpack/lib/action_view/helpers/date_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • date


File: debug_helper.rb

File
debug_helper.rb
Path: | actionpack/lib/action_view/helpers/debug_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: form_helper.rb

File
form_helper.rb
Path: | actionpack/lib/action_view/helpers/form_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • action_view/helpers/date_helper
  • action_view/helpers/tag_helper


File: form_options_helper.rb

File
form_options_helper.rb
Path: | actionpack/lib/action_view/helpers/form_options_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • erb
  • action_view/helpers/form_helper


File: form_tag_helper.rb

File
form_tag_helper.rb
Path: | actionpack/lib/action_view/helpers/form_tag_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • action_view/helpers/tag_helper


File: javascript_helper.rb

File
javascript_helper.rb
Path: | actionpack/lib/action_view/helpers/javascript_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_view/helpers/tag_helper
  • action_view/helpers/prototype_helper


File: number_helper.rb

File
number_helper.rb
Path: | actionpack/lib/action_view/helpers/number_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: prototype_helper.rb

File
prototype_helper.rb
Path: | actionpack/lib/action_view/helpers/prototype_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • set


File: record_identification_helper.rb

File
record_identification_helper.rb
Path: | actionpack/lib/action_view/helpers/record_identification_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: record_tag_helper.rb

File
record_tag_helper.rb
Path: | actionpack/lib/action_view/helpers/record_tag_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: sanitize_helper.rb

File
sanitize_helper.rb
Path: | actionpack/lib/action_view/helpers/sanitize_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_view/helpers/tag_helper
  • html/document


File: scriptaculous_helper.rb

File
scriptaculous_helper.rb
Path: | actionpack/lib/action_view/helpers/scriptaculous_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_view/helpers/javascript_helper


File: tag_helper.rb

File
tag_helper.rb
Path: | actionpack/lib/action_view/helpers/tag_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • cgi
  • erb


File: text_helper.rb

File
text_helper.rb
Path: | actionpack/lib/action_view/helpers/text_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_view/helpers/tag_helper
  • html/document


File: url_helper.rb

File
url_helper.rb
Path: | actionpack/lib/action_view/helpers/url_helper.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • action_view/helpers/javascript_helper


File: partials.rb

File
partials.rb
Path: | actionpack/lib/action_view/partials.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: template_error.rb

File
template_error.rb
Path: | actionpack/lib/action_view/template_error.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: template_handler.rb

File
template_handler.rb
Path: | actionpack/lib/action_view/template_handler.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: builder.rb

File
builder.rb
Path: | actionpack/lib/action_view/template_handlers/builder.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • builder


File: erb.rb

File
erb.rb
Path: | actionpack/lib/action_view/template_handlers/erb.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008

Required Files
  • erb


File: rjs.rb

File
rjs.rb
Path: | actionpack/lib/action_view/template_handlers/rjs.rb
Modified: | Sun Mar 02 11:08:58 -0700 2008


File: CHANGELOG

File
CHANGELOG
Path: | actionpack/CHANGELOG
Modified: | Sun Mar 02 11:08:57 -0700 2008

*2.0.2* (December 16th, 2007)

  • Added delete_via_redirect and put_via_redirect to integration testing 10497 [philodespotos]
  • Allow headers[‘Accept’] to be set by hand when calling xml_http_request 10461 [BMorearty]
  • Added OPTIONS to list of default accepted HTTP methods 10449 [holoway]
  • Added option to pass proc to ActionController::Base.asset_host for maximum configurability 10521 [chuyeow]. Example:
      ActionController::Base.asset_host = Proc.new { |source|
    if source.starts_with?('/images')
      "http://images.example.com"
    else
      "http://assets.example.com"
    end
  }
  • Fixed that ActionView#file_exists? would be incorrect if @first_render is set 10569 [dbussink]
  • Added that Array#to_param calls to_param on all it‘s elements 10473 [brandon]
  • Ensure asset cache directories are automatically created. 10337 [Josh Peek, Cheah Chu Yeow]
  • render :xml and :json preserve custom content types. 10388 [jmettraux, Cheah Chu Yeow]
  • Refactor Action View template handlers. 10437, 10455 [Josh Peek]
  • Fix DoubleRenderError message and leave out mention of returning false from filters. Closes 10380 [Frederick Cheung]
  • Clean up some cruft around ActionController::Base#head. Closes 10417 [ssoroka]

*2.0.1* (December 7th, 2007)

  • Fixed send_file/binary_content for testing 8044 [tolsen]
  • When a NonInferrableControllerError is raised, make the proposed fix clearer in the error message. Closes 10199 [danger]
  • Update Prototype to 1.6.0.1. [sam]
  • Update script.aculo.us to 1.8.0.1. [madrobby]
  • Add ‘disabled’ attribute to <OPTION> separators used in time zone and country selects. Closes 10354 [hasmanyjosh]
  • Added the same record identification guessing rules to fields_for as form_for has [DHH]
  • Fixed that verification violations with no specified action didn‘t halt the chain (now they do with a 400 Bad Request) [DHH]
  • Raise UnknownHttpMethod exception for unknown HTTP methods. Closes 10303 [Tarmo Tänav]
  • Update to Prototype -r8232. [sam]
  • Make sure the optimisation code for routes doesn‘t get used if :host, :anchor or :port are provided in the hash arguments. [pager, Koz] 10292
  • Added protection from trailing slashes on page caching 10229 [devrieda]
  • Asset timestamps are appended, not prepended. Closes 10276 [mnaberez]
  • Minor inconsistency in description of render example. Closes 10029 [ScottSchram]
  • Add prepend_view_path and append_view_path instance methods on ActionController::Base for consistency with the class methods. [rick]
  • Refactor sanitizer helpers into HTML classes and make it easy to swap them out with custom implementations. Closes 10129. [rick]
  • Add deprecation for old subtemplate syntax for ActionMailer templates, use render :partial [rick]
  • Fix TemplateError so it doesn‘t bomb on exceptions while running tests [rick]
  • Fixed that named routes living under resources shouldn‘t have double slashes 10198 [isaacfeliu]
  • Make sure that cookie sessions use a secret that is at least 30 chars in length. [Koz]
  • Fixed that partial rendering should look at the type of the first render to determine its own type if no other clues are available (like when using text.plain.erb as the extension in AM) 10130 [java]
  • Fixed that has_many :through associations should render as collections too 9051 [mathie/danger]
  • Added :mouseover short-cut to AssetTagHelper#image_tag for doing easy image swaps 6893 [joost]
  • Fixed handling of non-domain hosts 9479 [purp]
  • Fix syntax error in documentation example for cycle method. Closes 8735 [foca]
  • Document :with option for link_to_remote. Closes 8765 [ryanb]
  • Document :minute_step option for time_select. Closes 8814 [brupm]
  • Explain how to use the :href option for link_to_remote to degrade gracefully in the absence of JavaScript. Closes 8911 [vlad]
  • Disambiguate :size option for text area tag. Closes 8955 [redbeard]
  • Fix broken tag in assert_tag documentation. Closes 9037 [mfazekas]
  • Add documentation for route conditions. Closes 9041 [innu, manfred]
  • Fix typo left over from previous typo fix in url helper. Closes 9414 [Henrik N]
  • Fixed that ActionController::CgiRequest#host_with_port() should handle standard port 10082 [moro]
  • Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. [sam, madrobby]
  • Expose the cookie jar as a helper method (before the view would just get the raw cookie hash) [DHH]
  • Integration tests: get_ and post_via_redirect take a headers hash. 9130 [simonjefford]
  • Simplfy view_paths implementation. ActionView templates get the exact object, not a dup. [Rick]
  • Update tests for ActiveSupport‘s JSON escaping change. [rick]
  • FormHelper‘s auto_index should use to_param instead of id_before_type_cast. Closes 9994 [mattly]
  • Doc typo fixes for ActiveRecordHelper. Closes 9973 [mikong]
  • Make example parameters in restful routing docs idiomatic. Closes 9993 [danger]
  • Make documentation comment for mime responders match documentation example. Closes 9357 [yon]
  • Introduce a new test case class for functional tests. ActionController::TestCase. [Koz]
  • Fix incorrect path in helper rdoc. Closes 9926 [viktor tron]
  • Partials also set ‘object’ to the default partial variable. 8823 [Nick Retallack, Jeremy Kemper]
  • Request profiler. [Jeremy Kemper]
      $ cat login_session.rb
  get_with_redirect '/'
  say "GET / => #{path}"
  post_with_redirect '/sessions', :username => 'john', :password => 'doe'
  say "POST /sessions => #{path}"
  $ ./script/performance/request -n 10 login_session.rb
  • Disabled checkboxes don‘t submit a form value. 9301 [vladr, robinjfisher]
  • Added tests for options to ActiveRecordHelper#form. Closes 7213 [richcollins, mikong, mislav]
  • Changed before_filter halting to happen automatically on render or redirect but no longer on simply returning false [DHH]
  • Ensure that cookies handle array values correctly. Closes 9937 [queso]
  • Make sure resource routes don‘t clash with internal helpers like javascript_path, image_path etc. 9928 [gbuesing]
  • caches_page uses a single after_filter instead of one per action. 9891 [Pratik Naik]
  • Update Prototype to 1.6.0_rc1 and script.aculo.us to 1.8.0 preview 0. [sam, madrobby]
  • Dispatcher: fix that to_prepare should only run once in production. 9889 [Nathaniel Talbott]
  • Memcached sessions: add session data on initialization; don‘t silently discard exceptions; add unit tests. 9823 [kamk]
  • error_messages_for also takes :message and :header_message options which defaults to the old "There were problems with the following fields:" and "<count> errors prohibited this <object_name> from being saved". 8270 [rmm5t, zach-inglis-lt3]
  • Make sure that custom inflections are picked up by map.resources. 9815 [mislav]
  • Changed SanitizeHelper#sanitize to only allow the custom attributes and tags when specified in the call [DHH]
  • Extracted sanitization methods from TextHelper to SanitizeHelper [DHH]
  • rescue_from accepts :with => lambda { |exception| … } or a normal block. 9827 [Pratik Naik]
  • Add :status to redirect_to allowing users to choose their own response code without manually setting headers. 8297 [codahale, chasgrundy]
  • Add link_to :back which uses your referrer with a fallback to a javascript link. 7366 [eventualbuddha, Tarmo Tänav]
  • error_messages_for and friends also work with local variables. 9699 [Frederick Cheung]
  • Fix url_for, redirect_to, etc. with :controller => :symbol instead of ‘string’. 8562, 9525 [Justin Lynn, Tarmo Tänav, shoe]
  • Use require_library_or_gem to load the memcache library for the MemCache session and fragment cache stores. Closes 8662. [Rick]
  • Move ActionController::Routing.optimise_named_routes to ActionController::Base.optimise_named_routes. Now you can set it in the config. [Rick]

    config.action_controller.optimise_named_routes = false

  • ActionController::Routing::DynamicSegment#interpolation_chunk should call to_s on all values before calling URI.escape. [Rick]
  • Only accept session ids from cookies, prevents session fixation attacks. [bradediger]

*2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.12.2 - 1.13.3]

  • Fixed that render template did not honor exempt_from_layout 9698 [pezra]
  • Better error messages if you leave out the :secret option for request forgery protection. Closes 9670 [rick]
  • Allow ability to disable request forgery protection, disable it in test mode by default. Closes 9693 [Pratik Naik]
  • Avoid calling is_missing on LoadErrors. Closes 7460. [ntalbott]
  • Move Railties’ Dispatcher to ActionController::Dispatcher, introduce before_ and after_dispatch callbacks, and warm up to non-CGI requests. [Jeremy Kemper]
  • The tag helper may bypass escaping. [Jeremy Kemper]
  • Cache asset ids. [Jeremy Kemper]
  • Optimized named routes respect AbstractRequest.relative_url_root. 9612 [danielmorrison, Jeremy Kemper]
  • Introduce ActionController::Base.rescue_from to declare exception-handling methods. Cleaner style than the case-heavy rescue_action_in_public. 9449 [Norbert Crombach]
  • Rename some RequestForgeryProtection methods. The class method is now protect_from_forgery, and the default parameter is now ‘authenticity_token’. [Rick]
  • Merge csrf_killer plugin into rails. Adds RequestForgeryProtection model that verifies session-specific _tokens for non-GET requests. [Rick]
  • Secure sanitize, strip_tags, and strip_links helpers against xss attacks. Closes 8877. [Rick, Pratik Naik, Jacques Distler]

    This merges and renames the popular white_list helper (along with some css sanitizing from Jacques Distler version of the same plugin). Also applied updated versions of strip_tags and strip_links from 8877.

  • Remove use of & logic operator. Closes 8114. [watson]
  • Fixed JavaScriptHelper#escape_javascript to also escape closing tags 8023 [rubyruy]
  • Fixed TextHelper#word_wrap for multiline strings with extra carrier returns 8663 [seth]
  • Fixed that setting the :host option in url_for would automatically turn off :only_path (since :host would otherwise not be shown) 9586 [Bounga]
  • Added FormHelper#label. 8641, 9850 [jcoglan, jarkko]
  • Added AtomFeedHelper (slightly improved from the atom_feed_helper plugin) [DHH]
  • Prevent errors when generating routes for uncountable resources, (i.e. sheep where plural == singluar). map.resources :sheep now creates sheep_index_url for the collection and sheep_url for the specific item. [Koz]
  • Added support for HTTP Only cookies (works in IE6+ and FF 2.0.5+) as an improvement for XSS attacks 8895 [Pratik Naik, Spakman]
  • Don‘t warn when a path segment precedes a required segment. Closes 9615. [Nicholas Seckar]
  • Fixed CaptureHelper#content_for to work with the optional content parameter instead of just the block 9434 [sandofsky/wildchild].
  • Added Mime::Type.register_alias for dealing with different formats using the same mime type [DHH]. Example:
      class PostsController < ApplicationController
    before_filter :adjust_format_for_iphone

    def index
      @posts = Post.find(:all)

      respond_to do |format|
        format.html   # => renders index.html.erb and uses "text/html" as the content type
        format.iphone # => renders index.iphone.erb and uses "text/html" as the content type
      end
    end

    private
      def adjust_format_for_iphone
        if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/iPhone/]
          request.format = :iphone
        end
      end
  end
  • Added that render :json will automatically call .to_json unless it‘s being passed a string [DHH].
  • Autolink behaves well with emails embedded in URLs. 7313 [Jeremy McAnally, Tarmo Tänav]
  • Fixed that default layouts did not take the format into account 9564 [Pratik Naik]
  • Fixed optimized route segment escaping. 9562 [wildchild, Jeremy Kemper]
  • Added block acceptance to JavaScriptHelper#javascript_tag. 7527 [Bob Silva, Tarmo Tänav, rmm5t]
  • root_path returns ’/’ not ’’. 9563 [Pratik Naik]
  • Fixed that setting request.format should also affect respond_to blocks [DHH]
  • Add option to force binary mode on tempfile used for fixture_file_upload. 6380 [Jonathan Viney]
  • Fixed that resource namespaces wouldn‘t stick to all nested resources 9399 [pixeltrix]
  • Moved ActionController::Macros::AutoComplete into the auto_complete plugin on the official Rails svn. 9512 [Pratik Naik]
  • Moved ActionController::Macros::InPlaceEditing into the in_place_editor plugin on the official Rails svn. 9513 [Pratik Naik]
  • Removed deprecated form of calling xml_http_request/xhr without the first argument being the http verb [DHH]
  • Removed deprecated methods [DHH]:
    • ActionController::Base#keep_flash (use flash.keep instead)
    • ActionController::Base#expire_matched_fragments (just call expire_fragment with a regular expression)
    • ActionController::Base.template_root/= methods (use ActionController#Base.view_paths/= instead)
    • ActionController::Base.cookie (use ActionController#Base.cookies[]= instead)
  • Removed the deprecated behavior of appending ".png" to image_tag/image_path calls without an existing extension [DHH]
  • Removed ActionController::Base.scaffold — it went through the whole idea of scaffolding (card board walls you remove and tweak one by one). Use the scaffold generator instead (it does resources too now!) [DHH]
  • Optimise named route generation when using positional arguments. [Koz]

    This change delivers significant performance benefits for the most common usage scenarios for modern rails applications by avoiding the costly trip through url_for. Initial benchmarks indicate this is between 6 and 20 times as fast.

  • Explicitly require active_record/query_cache before using it. [Jeremy Kemper]
  • Fix layout overriding response status. 9476 [lotswholetime]
  • Add field_set_tag for generating field_sets, closes 9477. [djanowski]
  • Allow additional parameters to be passed to named route helpers when using positional arguments. Closes 8930 [ian.w.white@gmail.com]
  • Make render :partial work with a :collection of Hashes, previously this wasn‘t possible due to backwards compatibility restrictions. [Pratik Naik]
  • request.host works with IPv6 addresses. 9458 [yuya]
  • Fix bug where action caching sets the content type to the ActionCachePath object. Closes 9282 [mindforge]
  • Find layouts even if they‘re not in the first view_paths directory. Closes 9258 [caio]
  • Major improvement to the documentation for the options / select form helpers. Closes 9038 [kampers, jardeon, wesg]
  • Fix number_to_human_size when using different precisions. Closes 7536. [RichardStrand, mpalmer]
  • Added partial layouts (see example in action_view/lib/partials.rb) [DHH]
  • Allow you to set custom :conditions on resource routes. [Rick]
  • Fixed that file.content_type for uploaded files would include a trailing \r 9053 [bgreenlee]
  • url_for now accepts a series of symbols representing the namespace of the record [Josh Knowles]
  • Make :trailing_slash work with query parameters for url_for. Closes 4004 [nov]
  • Make sure missing template exceptions actually say which template they were looking for. Closes 8683 [dasil003]
  • Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes 8891 [skaes]

    After filters will *no longer* be run if an around_filter fails to yield, users relying on this behaviour are advised to put the code in question after a yield statement in an around filter.

  • Allow you to delete cookies with options. Closes 3685 [Josh Peek, Chris Wanstrath]
  • Allow you to render views with periods in the name. Closes 8076 [Norbert Crombach]

    render :partial => ‘show.html.erb‘

  • Improve capture helper documentation. 8796 [kampers]
  • Prefix nested resource named routes with their action name, e.g. new_group_user_path(@group) instead of group_new_user_path(@group). The old nested action named route is deprecated in Rails 1.2.4. 8558 [David Chelimsky]
  • Allow sweepers to be created solely for expiring after controller actions, not model changes [DHH]
  • Added assigns method to ActionController::Caching::Sweeper to easily access instance variables on the controller [DHH]
  • Give the legacy X-POST_DATA_FORMAT header greater precedence during params parsing for backward compatibility. [Jeremy Kemper]
  • Fixed that link_to with an href of # when using :method will not allow for click-through without JavaScript 7037 [Steven Bristol, Josh Peek]
  • Fixed that radio_button_tag should generate unique ids 3353 [Bob Silva, Rebecca, Josh Peek]
  • Fixed that HTTP authentication should work if the header is called REDIRECT_X_HTTP_AUTHORIZATION as well 6754 [mislaw]
  • Don‘t mistakenly interpret the request uri as the query string. 8731 [Pratik Naik, Jeremy Kemper]
  • Make ActionView#view_paths an attr_accessor for real this time. Also, don‘t perform an unnecessary compact on the @view_paths array in initialize. Closes 8582 [dasil003, julik, rick]
  • Tolerate missing content type on multipart file uploads. Fix for Safari 3. [Jeremy Kemper]
  • Deprecation: remove pagination. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. 8157 [Josh Peek]
  • Action caching is limited to GET requests returning 200 OK status. 3335 [tom@craz8.com, halfbyte, Dan Kubb, Josh Peek]
  • Improve Text Helper test coverage. 7274 [Rob Sanheim, Josh Peek]
  • Improve helper test coverage. 7208, 7212, 7215, 7233, 7234, 7235, 7236, 7237, 7238, 7241, 7243, 7244 [Rich Collins, Josh Peek]
  • Improve UrlRewriter tests. 7207 [Rich Collins]
  • Resources: url_for([parent, child]) generates /parents/1/children/2 for the nested resource. Likewise with the other simply helpful methods like form_for and link_to. 6432 [mhw, Jonathan Vaught, lotswholetime]
  • Assume html format when rendering partials in RJS. 8076 [Rick]
  • Don‘t double-escape url_for in views. 8144 [Rich Collins, Josh Peek]
  • Allow JSON-style values for the :with option of observe_field. Closes 8557 [kommen]
  • Remove RAILS_ROOT from backtrace paths. 8540 [Tim Pope]
  • Routing: map.resource :logo routes to LogosController so the controller may be reused for multiple nestings or namespaces. [Jeremy Kemper]
  • render :partial recognizes Active Record associations as Arrays. 8538 [Kamal Fariz Mahyuddin]
  • Routing: drop semicolon and comma as route separators. [Jeremy Kemper]
  • request.remote_ip understands X-Forwarded-For addresses with nonstandard whitespace. 7386 [moses]
  • Don‘t prepare response when rendering a component. 8493 [jsierles]
  • Reduce file stat calls when checking for template changes. 7736 [alex]
  • Added custom path cache_page/expire_page parameters in addition to the options hashes [DHH]. Example:
      def index
    caches_page(response.body, "/index.html")
  end
  • Action Caching speedup. 8231 [skaes]
  • Wordsmith resources documentation. 8484 [marclove]
  • Fix syntax error in code example for routing documentation. 8377. [Norbert Crombach]
  • Routing: respond with 405 Method Not Allowed status when the route path matches but the HTTP method does not. 6953 [Josh Peek, defeated, Dan Kubb, Coda Hale]
  • Add support for assert_select_rjs with :show and :hide. 7780 [dchelimsky]
  • Make assert_select‘s failure messages clearer about what failed. 7779 [dchelimsky]
  • Introduce a default respond_to block for custom types. 8174 [Josh Peek]
  • auto_complete_field takes a :method option so you can GET or POST. 8120 [zapnap]
  • Added option to suppress :size when using :maxlength for FormTagHelper#text_field 3112 [Tim Pope]
  • catch possible WSOD when trying to render a missing partial. Closes 8454 [Catfish]
  • Rewind request body after reading it, if possible. 8438 [s450r1]
  • Resource namespaces are inherited by their has_many subresources. 8280 [marclove, ggarside]
  • Fix filtered parameter logging with nil parameter values. 8422 [choonkeat]
  • Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. 7124 [Nik Wakelin, Francois Beausoleil, Wizard]
  • Document caches_action. 5419 [Jarkko Laine]
  • Update to Prototype 1.5.1. [Sam Stephenson]
  • Allow routes to be decalred under namespaces [Tobias Luetke]:

    map.namespace :admin do |admin|

      admin.root :controller => "products"
  admin.feed 'feed.xml', :controller => 'products', :action => 'feed', :format => 'xml'

    end

  • Update to script.aculo.us 1.7.1_beta3. [Thomas Fuchs]
  • observe_form always sends the serialized form. 5271 [manfred, normelton@gmail.com]
  • Parse url-encoded and multipart requests ourselves instead of delegating to CGI. [Jeremy Kemper]
  • select :include_blank option can be set to a string instead of true, which just uses an empty string. 7664 [Wizard]
  • Added url_for usage on render :location, which allows for record identification [DHH]. Example:
      render :xml => person, :status => :created, :location => person

    …expands the location to person_url(person).

  • Introduce the request.body stream. Lazy-read to parse parameters rather than always setting RAW_POST_DATA. Reduces the memory footprint of large binary PUT requests. [Jeremy Kemper]
  • Add some performance enhancements to ActionView.
    • Cache base_paths in @@cached_base_paths
    • Cache template extensions in @@cached_template_extension
    • Remove unnecessary rescues
  • Assume that rendered partials go by the HTML format by default

    def my_partial

      render :update do |page|
    # in this order
    # _foo.html.erb
    # _foo.erb
    # _foo.rhtml
    page.replace :foo, :partial => 'foo'
  end

    end

  • Added record identifications to FormHelper#form_for and PrototypeHelper#remote_form_for [DHH]. Examples:
      <% form_for(@post) do |f| %>
    ...
  <% end %>

    This will expand to be the same as:

      <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
    ...
  <% end %>

    And for new records:

      <% form_for(Post.new) do |f| %>
    ...
  <% end %>

    This will expand to be the same as:

      <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %>
    ...
  <% end %>
  • Rationalize route path escaping according to RFC 2396 section 3.3. 7544, 8307. [Jeremy Kemper, chrisroos, begemot, jugend]
  • Added record identification with polymorphic routes for ActionController::Base#url_for and ActionView::Base#url_for [DHH]. Examples:
      redirect_to(post)         # => redirect_to(posts_url(post))         => Location: http://example.com/posts/1
  link_to(post.title, post) # => link_to(post.title, posts_url(post)) => <a href="/posts/1">Hello world</a>

    Any method that calls url_for on its parameters will automatically benefit from this.

  • Removed deprecated parameters_for_method_reference concept (legacy from before named routes) [DHH]
  • Add ActionController::Routing::Helpers, a module to contain common URL helpers such as polymorphic_url. [Nicholas Seckar]
  • Included the HttpAuthentication plugin as part of core (ActionController::HttpAuthentication::Basic) [DHH]
  • Modernize documentation for form helpers. [jeremymcanally]
  • Add brief introduction to REST to the resources documentation. [fearoffish]
  • Fix various documentation typos throughout ActionPack. [Henrik N]
  • Enhance documentation and add examples for url_for. [jeremymcanally]
  • Fix documentation typo in routes. [Norbert Crombach, pam]
  • Sweep flash when filter chain is halted. [Caio Chassot <lists@v2studio.com>]
  • Fixed that content_tag with a block will just return the result instead of concate it if not used in a ERb view 7857, 7432 [michael.niessner]
  • Replace the current block/continuation filter chain handling by an implementation based on a simple loop. 8226 [Stefan Kaes]
  • Update UrlWriter to accept :anchor parameter. Closes 6771. [octopod]
  • Added RecordTagHelper for using RecordIdentifier conventions on divs and other container elements [DHH]. Example:
      <% div_for(post) do %>     <div id="post_45" class="post">
    <%= post.body %>           What a wonderful world!
  <% end %>                  </div>
  • Added page[record] accessor to JavaScriptGenerator that relies on RecordIdentifier to find the right dom id [DHH]. Example:
      format.js do
    # Calls: new Effect.fade('post_45');
    render(:update) { |page| page[post].visual_effect(:fade) }
  end
  • Added RecordIdentifier to enforce view conventions on records for dom ids, classes, and partial paths [DHH]
  • Added map.namespace to deal with the common situation of admin sections and the like [DHH]
      Before:

    map.resources :products, :path_prefix => "admin", :controller => "admin/products", :collection => { :inventory => :get }, :member => { :duplicate => :post }
    map.resources :tags, :name_prefix => 'admin_product_', :path_prefix => "admin/products/:product_id", :controller => "admin/product_tags"
    map.resources :images, :name_prefix => 'admin_product_', :path_prefix => "admin/products/:product_id", :controller => "admin/product_images"
    map.resources :variants, :name_prefix => 'admin_product_', :path_prefix => "admin/products/:product_id", :controller => "admin/product_variants"

  After:

    map.namespace(:admin) do |admin|
      admin.resources :products,
        :collection => { :inventory => :get },
        :member     => { :duplicate => :post },
        :has_many   => [ :tags, :images, :variants ]
    end
  • Added :name_prefix as standard for nested resources [DHH]. WARNING: May be backwards incompatible with your app
      Before:

    map.resources :emails do |emails|
      emails.resources :comments,    :name_prefix => "email_"
      emails.resources :attachments, :name_prefix => "email_"
    end

  After:

    map.resources :emails do |emails|
      emails.resources :comments
      emails.resources :attachments
    end

  This does mean that if you intended to have comments_url go to /emails/5/comments, then you'll have to set :name_prefix to nil explicitly.
  • Added :has_many and :has_one for declaring plural and singular resources beneath the current [DHH]
      Before:

    map.resources :notes do |notes|
      notes.resources :comments
      notes.resources :attachments
      notes.resource :author
    end

  After:

    map.resources :notes, :has_many => [ :comments, :attachments ], :has_one => :author
  • Added that render :xml will try to call to_xml if it can [DHH]. Makes these work:
      render :xml => post
  render :xml => comments
  • Added :location option to render so that the common pattern of rendering a response after creating a new resource is now a 1-liner [DHH]
      render :xml => post.to_xml, :status => :created, :location => post_url(post)
  • Ensure that render_text only adds string content to the body of the response [DHH]
  • Return the string representation from an Xml Builder when rendering a partial. Closes 5044 [Tim Pope]
  • Fixed that parameters from XML should also be presented in a hash with indifferent access [DHH]
  • Tweak template format rules so that the ACCEPT header is only used if it‘s text/javascript. This is so ajax actions without a :format param get recognized as Mime::JS. [Rick]
  • The default respond_to blocks don‘t set a specific extension anymore, so that both ‘show.rjs’ and ‘show.js.rjs’ will work. [Rick]
  • Allow layouts with extension of .html.erb. Closes 8032 [Josh Knowles]
  • Change default respond_to templates for xml and rjs formats. [Rick]
    • Default xml template goes from #{action_name}.rxml => #{action_name}.xml.builder.
    • Default rjs template goes from #{action_name}.rjs => #{action_name}.js.rjs.

    You can still specify your old templates:

      respond_to do |format|
    format.xml do
      render :action => "#{action_name}.rxml"
    end
  end
  • Fix WSOD due to modification of a formatted template extension so that requests to templates like ‘foo.html.erb’ fail on the second hit. [Rick]
  • Fix WSOD when template compilation fails [Rick]
  • Change ActionView template defaults. Look for templates using the request format first, such as "show.html.erb" or "show.xml.builder", before looking for the old defaults like "show.erb" or "show.builder" [Rick]
  • Highlight helper highlights one or many terms in a single pass. [Jeremy Kemper]
  • Dropped the use of ; as a separator of non-crud actions on resources and went back to the vanilla slash. It was a neat idea, but lots of the non-crud actions turned out not to be RPC (as the ; was primarily intended to discourage), but legitimate sub-resources, like /parties/recent, which didn‘t deserve the uglification of /parties;recent. Further more, the semicolon caused issues with caching and HTTP authentication in Safari. Just Not Worth It [DHH]
  • Added that FormTagHelper#submit_tag will return to its original state if the submit fails and you‘re using :disable_with [DHH]
  • Cleaned up, corrected, and mildly expanded ActionPack documentation. Closes 7190 [jeremymcanally]
  • Small collection of ActionController documentation cleanups. Closes 7319 [jeremymcanally]
  • Make sure the route expiry hash is constructed by comparing the to_param-ized values of each hash. [Jamis Buck]
  • Allow configuration of the default action cache path for caches_action calls. [Rick Olson]

    class ListsController < ApplicationController

      caches_action :index, :cache_path => Proc.new { |controller|
    controller.params[:user_id] ?
      controller.send(:user_lists_url, c.params[:user_id]) :
      controller.send(:lists_url) }

    end

  • Performance: patch cgi/session/pstore to require digest/md5 once rather than per initialize. 7583 [Stefan Kaes]
  • Cookie session store: ensure that new sessions doesn‘t reuse data from a deleted session in the same request. [Jeremy Kemper]
  • Deprecation: verification with :redirect_to => :named_route shouldn‘t be deprecated. 7525 [Justin French]
  • Cookie session store: raise ArgumentError when :session_key is blank. [Jeremy Kemper]
  • Deprecation: remove deprecated request, redirect, and dependency methods. Remove deprecated instance variables. Remove deprecated url_for(:symbol, *args) and redirect_to(:symbol, *args) in favor of named routes. Remove uses_component_template_root for toplevel components directory. Privatize deprecated render_partial and render_partial_collection view methods. Remove deprecated link_to_image, link_image_to, update_element_function, start_form_tag, and end_form_tag helper methods. Remove deprecated human_size helper alias. [Jeremy Kemper]
  • Consistent public/protected/private visibility for chained methods. 7813 [Dan Manges]
  • Prefer MIME constants to strings. 7707 [Dan Kubb]
  • Allow array and hash query parameters. Array route parameters are converted/to/a/path as before. 6765, 7047, 7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan]

# Add a dbman attr_reader for CGI::Session and make CGI::Session::CookieStore#generate_digest public so it‘s easy to generate digests using the cookie store‘s secret. [Rick]

  • Added Request#url that returns the complete URL used for the request [DHH]
  • Extract dynamic scaffolding into a plugin. 7700 [Josh Peek]
  • Added user/password options for url_for to add http authentication in a URL [DHH]
  • Fixed that FormTagHelper#text_area_tag should disregard :size option if it‘s not a string [Brendon Davidson]
  • Set the original button value in an attribute of the button when using the :disable_with key with submit_tag, so that the original can be restored later. [Jamis Buck]
  • session_enabled? works with session :off. 6680 [Catfish]
  • Added :port and :host handling to UrlRewriter (which unified url_for usage, regardless of whether it‘s called in view or controller) 7616 [alancfrancis]
  • Allow send_file/send_data to use a registered mime type as the :type parameter 7620 [jonathan]
  • Allow routing requirements on map.resource(s) 7633 [quixoten]. Example:

    map.resources :network_interfaces, :requirements => { :id => /^\d+\.\d+\.\d+\.\d+$/ }

  • Cookie session store: empty and unchanged sessions don‘t write a cookie. [Jeremy Kemper]
  • Added helper(:all) as a way to include all helpers from app/helpers/**/*.rb in ApplicationController [DHH]
  • Integration tests: introduce methods for other HTTP methods. 6353 [caboose]
  • Routing: better support for escaped values in route segments. 7544 [Chris

Roos]

  • Introduce a cookie-based session store as the Rails default. Sessions typically contain at most a user_id and flash message; both fit within the 4K cookie size limit. A secure message digest is included with the cookie to ensure data integrity (a user cannot alter his user_id without knowing the secret key included in the digest). If you have more than 4K of session data or don‘t want your data to be visible to the user, pick another session store. Cookie-based sessions are dramatically faster than the alternatives. [Jeremy Kemper]

    Example config/environment.rb:

      # Use an application-wide secret key and the default SHA1 message digest.
  config.action_controller.session = { :secret => "can't touch this" }

  # Store a secret key per user and employ a stronger message digest.
  config.action_controller.session = {
    :digest => 'SHA512',
    :secret => Proc.new { User.current.secret_key }
  }
  • Added .erb and .builder as preferred aliases to the now deprecated .rhtml and .rxml extensions [Chad Fowler]. This is done to separate the renderer from the mime type. .erb templates are often used to render emails, atom, csv, whatever. So labeling them .rhtml doesn‘t make too much sense. The same goes for .rxml, which can be used to build everything from HTML to Atom to whatever. .rhtml and .rxml will continue to work until Rails 3.0, though. So this is a slow phasing out. All generators and examples will start using the new aliases, though.
  • Added caching option to AssetTagHelper#stylesheet_link_tag and AssetTagHelper#javascript_include_tag [DHH]. Examples:
      stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
    <link href="/stylesheets/style1.css"  media="screen" rel="Stylesheet" type="text/css" />
    <link href="/stylesheets/styleB.css"  media="screen" rel="Stylesheet" type="text/css" />
    <link href="/stylesheets/styleX2.css" media="screen" rel="Stylesheet" type="text/css" />

  stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is true =>
    <link href="/stylesheets/all.css"  media="screen" rel="Stylesheet" type="text/css" />

    …when caching is on, all.css is the concatenation of style1.css, styleB.css, and styleX2.css. Same deal for JavaScripts.

  • Work around the two connection per host browser limit: use asset%d.myapp.com to distribute asset requests among asset[0123].myapp.com. Use a DNS wildcard or CNAMEs to map these hosts to your asset server. See www.die.net/musings/page_load_time/ for background. [Jeremy Kemper]
  • Added default mime type for CSS (Mime::CSS) [DHH]
  • Added that rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified and the response body will be set to an empty string. [DHH]
  • Added X-Runtime to all responses with the request run time [DHH]
  • Add Mime::Type convenience methods to check the current mime type. [Rick]

    request.format.html? # => true if Mime::HTML request.format.jpg? # => true if Mime::JPG

    # ActionController sample usage: # the session will be disabled for non html/ajax requests session :off, :if => Proc.new { |req| !(req.format.html? || req.format.js?) }

  • Performance: patch cgi/session to require digest/md5 once rather than per create_new_id. [Stefan Kaes]
  • Add a :url_based_filename => true option to ActionController::Streaming::send_file, which allows URL-based filenames. [Thomas Fuchs]
  • Fix that FormTagHelper#submit_tag using :disable_with should trigger the onsubmit handler of its form if available [DHH]
  • Fix render_file so that TemplateError is called with the correct params and you don‘t get the WSOD. [Rick]
  • Fix issue with deprecation messing up template_root= usage. Add prepend_view_path and append_view_path to allow modification of a copy of the

superclass’ view_paths. [Rick]

  • Allow Controllers to have multiple view_paths instead of a single template_root. Closes 2754 [John Long]
  • Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
  • improve error message for Routing for named routes. Closes 7346 [Rob Sanheim]
  • Added enhanced docs to routing assertions. Closes 7359 [Rob Sanheim]
  • fix form_for example in ActionController::Resources documentation. Closes 7362 [gnarg]
  • Make sure that the string returned by TextHelper#truncate is actually a string, not a char proxy — that should only be used internally while working on a multibyte-safe way of truncating [DHH]
  • Added FormBuilder#submit as a delegate for FormTagHelper#submit_tag [DHH]
  • Allow Routes to generate all urls for a set of options by specifying :generate_all => true. Allows caching to properly set or expire all paths for a resource. References 1739. [Nicholas Seckar]
  • Change the query parser to map empty GET params to "" rather than nil. Closes 5694. [Nicholas Seckar]
  • date_select and datetime_select take a :default option. 7052 [nik.wakelin]
      date_select "post", "written_on", :default => 3.days.from_now
  date_select "credit_card", "bill_due", :default => { :day => 20 }
  • select :multiple => true suffixes the attribute name with [] unless already suffixed. 6977 [nik.kakelin, ben, julik]
  • Improve routes documentation. 7095 [zackchandler]
  • mail_to :encode => ‘hex’ also encodes the mailto: part of the href attribute as well as the linked email when no name is given. 2061 [Jarkko Laine, pfc.pille@gmx.net]
  • Resource member routes require :id, eliminating the ambiguous overlap with collection routes. 7229 [dkubb]
  • Remove deprecated assertions. [Jeremy Kemper]
  • Change session restoration to allow namespaced models to be autoloaded. Closes 6348. [Nicholas Seckar]
  • Fix doubly appearing parameters due to string and symbol mixups. Closes 2551. [aeden]
  • Fix overly greedy rescues when loading helpers. Fixes 6268. [Nicholas Seckar]
  • Fixed NumberHelper#number_with_delimiter to use "." always for splitting the original number, not the delimiter parameter 7389 [ceefour]
  • Autolinking recognizes trailing and embedded . , : ; 7354 [Jarkko Laine]
  • Make TextHelper::auto_link recognize URLs with colons in path correctly, fixes 7268. [imajes]
  • Update to script.aculo.us 1.7.0. [Thomas Fuchs]
  • Modernize cookie testing code, and increase coverage (Heckle++) 7101 [Kevin Clark]
  • Improve Test Coverage for ActionController::Routing::Route#matches_controller_and_action? (Heckle++) 7115 [Kevin Clark]
  • Heckling ActionController::Resources::Resource revealed that set_prefixes didn‘t break when :name_prefix was munged. 7081 [Kevin Clark]
  • Fix distance_of_time_in_words to report accurately against the Duration class. 7114 [eventualbuddha]
  • Refactor form_tag to allow easy extending. [Rick]
  • Update to Prototype 1.5.0. [Sam Stephenson]
  • RecordInvalid, RecordNotSaved => 422 Unprocessable Entity, StaleObjectError => 409 Conflict. 7097 [dkubb]
  • Allow fields_for to be nested inside form_for, so that the name and id get properly constructed [Jamis Buck]
  • Allow inGroupsOf and eachSlice to be called through rjs. 7046 [Cody Fauser]
  • Allow exempt_from_layout :rhtml. 6742, 7026 [Dan Manges, Squeegy]
  • Recognize the .txt extension as Mime::TEXT [Rick]
  • Fix parsing of array[] CGI parameters so extra empty values aren‘t included. 6252 [Nicholas Seckar, aiwilliams, brentrowland]
  • link_to_unless_current works with full URLs as well as paths. 6891 [Jarkko Laine, manfred, idrifter]
  • Lookup the mime type for auto_discovery_link_tag in the Mime::Type class. Closes 6941 [Josh Peek]
  • Fix bug where nested resources ignore a parent singleton parent‘s path prefix. Closes 6940 [Dan Kubb]
  • Fix no method error with error_messages_on. Closes 6935 [nik.wakelin Koz]
  • Slight doc tweak to the ActionView::Helpers::PrototypeHelper#replace docs. Closes 6922 [Steven Bristol]
  • Slight doc tweak to prepend_filter. Closes 6493 [Jeremy Voorhis]
  • Add more extensive documentation to the AssetTagHelper. Closes 6452 [Bob Silva]
  • Clean up multiple calls to stringify_keys in TagHelper, add better documentation and testing for TagHelper. Closes 6394 [Bob Silva]
  • [DOCS] fix reference to ActionController::Macros::AutoComplete for text_field_with_auto_complete. Closes 2578 [Jan Prill]
  • Make sure html_document is reset between integration test requests. [ctm]
  • Set session to an empty hash if :new_session => false and no session cookie or param is present. CGI::Session was raising an unrescued ArgumentError. [Josh Susser]
  • Routing uses URI escaping for path components and CGI escaping for query parameters. [darix, Jeremy Kemper]
  • Fix assert_redirected_to bug where redirecting from a nested to to a top-level controller incorrectly added the current controller‘s nesting. Closes 6128. [Rick Olson]
  • Singleton resources: POST /singleton => create, GET /singleton/new => new. [Jeremy Kemper]
  • Use 400 Bad Request status for unrescued ActiveRecord::RecordInvalid exceptions. [Jeremy Kemper]
  • Silence log_error deprecation warnings from inspecting deprecated instance variables. [Nate Wiger]
  • Only cache GET requests with a 200 OK response. 6514, 6743 [RSL, anamba]
  • Add a ‘referer’ attribute to TestRequest. [Jamis Buck]
  • Ensure render :json => … skips the layout. Closes 6808 [Josh Peek]
  • Fix HTML::Node to output double quotes instead of single quotes. Closes 6845 [mitreandy]
  • Correctly report which filter halted the chain. 6699 [Martin Emde]
  • Fix a bug in Routing where a parameter taken from the path of the current request could not be used as a query parameter for the next. Closes 6752. [Nicholas Seckar]
  • Unrescued ActiveRecord::RecordNotFound responds with 404 instead of 500. [Jeremy Kemper]
  • Improved auto_link to match more valid urls correctly [Tobias Luetke]
  • Add singleton resources. [Rick Olson]

    map.resource :account

    GET /account GET /account;edit UPDATE /account DELETE /account

  • respond_to recognizes JSON. render :json => @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. 4185 [Scott Raymond, eventualbuddha]
      # application/json response with body 'Element.show({:name: "David"})'
  respond_to do |format|
    format.json { render :json => { :name => "David" }.to_json, :callback => 'Element.show' }
  end
  • Makes :discard_year work without breaking multi-attribute parsing in AR. 1260, 3800 [sean@ardismg.com, jmartin@desertflood.com, stephen@touset.org, Bob Silva]
  • Adds html id attribute to date helper elements. 1050, 1382 [mortonda@dgrmm.net, David North, Bob Silva]
  • Add :index and @auto_index capability to model driven date/time selects. 847, 2655 [moriq, Doug Fales, Bob Silva]
  • Add :order to datetime_select, select_datetime, and select_date. 1427 [Timothee Peignier, patrick@lenz.sh, Bob Silva]
  • Added time_select to work with time values in models. Update scaffolding. 2489, 2833 [Justin Palmer, Andre Caum, Bob Silva]
  • Added :include_seconds to select_datetime, datetime_select and time_select. 2998 [csn, Bob Silva]
  • All date/datetime selects can now accept an array of month names with :use_month_names. Allows for localization. 363 [tomasj, Bob Silva]
  • Adds :time_separator to select_time and :date_separator to select_datetime. Preserves BC. 3811 [Bob Silva]
  • Added map.root as an alias for map.connect ’’ [DHH]
  • Added Request#format to return the format used for the request as a mime type. If no format is specified, the first Request#accepts type is used. This means you can stop using respond_to for anything else than responses [DHH]. Examples:
      GET /posts/5.xml   | request.format => Mime::XML
  GET /posts/5.xhtml | request.format => Mime::HTML
  GET /posts/5       | request.format => request.accepts.first (usually Mime::HTML for browsers)
  • Added the option for extension aliases to mime type registration [DHH]. Example (already in the default routes):
      Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )

    …will respond on both .html and .xhtml.

  • @response.redirect_url works with 201 Created responses: just return headers[‘Location’] rather than checking the response status. [Jeremy Kemper]
  • Added CSV to Mime::SET so that respond_to csv will work [Cody Fauser]
  • Fixed that HEAD should return the proper Content-Length header (that is, actually use @body.size, not just 0) [DHH]
  • Added GET-masquarading for HEAD, so request.method will return :get even for HEADs. This will help anyone relying on case request.method to automatically work with HEAD and map.resources will also allow HEADs to all GET actions. Rails automatically throws away the response content in a reply to HEAD, so you don‘t even need to worry about that. If you, for whatever reason, still need to distinguish between GET and HEAD in some edge case, you can use Request#head? and even Request.headers["REQUEST_METHOD"] for get the "real" answer. Closes 6694 [DHH]
  • Update Routing to complain when :controller is not specified by a route. Closes 6669. [Nicholas Seckar]
  • Ensure render_to_string cleans up after itself when an exception is raised. 6658 [Rob Sanheim]
  • Extract template_changed_since? from compile_template? so plugins may override its behavior for non-file-based templates. 6651 [Jeff Barczewski]
  • Update to Prototype and script.aculo.us [5579]. [Thomas Fuchs]
  • simple_format helper doesn‘t choke on nil. 6644 [jerry426]
  • Update to Prototype 1.5.0_rc2 [5550] which makes it work in Opera again [Thomas Fuchs]
  • Reuse named route helper module between Routing reloads. Use remove_method to delete named route methods after each load. Since the module is never collected, this fixes a significant memory leak. [Nicholas Seckar]
  • ActionView::Base.erb_variable accessor names the buffer variable used to render templates. Defaults to _erbout; use _buf for erubis. [Rick Olson]
  • assert_select_rjs :remove. [Dylan Egan]
  • Always clear model associations from session. 4795 [sd@notso.net, andylien@gmail.com]
  • Update to Prototype 1.5.0_rc2. [Sam Stephenson]
  • Remove JavaScriptLiteral in favor of ActiveSupport::JSON::Variable. [Sam Stephenson]
  • Sync ActionController::StatusCodes::STATUS_CODES with www.iana.org/assignments/http-status-codes. 6586 [dkubb]
  • Multipart form values may have a content type without being treated as uploaded files if they do not provide a filename. 6401 [Andreas Schwarz, Jeremy Kemper]
  • assert_response supports symbolic status codes. 6569 [Kevin Clark]
      assert_response :ok
  assert_response :not_found
  assert_response :forbidden
  • Cache parsed query parameters. 6559 [Stefan Kaes]
  • Deprecate JavaScriptHelper#update_element_function, which is superseeded by RJS [Thomas Fuchs]
  • pluralize helper interprets nil as zero. 6474 [Tim Pope]
  • Fix invalid test fixture exposed by stricter Ruby 1.8.5 multipart parsing. 6524 [Bob Silva]
  • Set ActionView::Base.default_form_builder once rather than passing the :builder option to every form or overriding the form helper methods. [Jeremy Kemper]
  • Deprecate expire_matched_fragments. Use expire_fragment instead. 6535 [Bob Silva]
  • Update to latest Prototype, which doesn‘t serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs]
  • Deprecate start_form_tag and end_form_tag. Use form_tag / ’</form>’ from now on. [Rick]
  • Added block-usage to PrototypeHelper#form_remote_tag, document block-usage of FormTagHelper#form_tag [Rick]
  • Add a 0 margin/padding div around the hidden _method input tag that form_tag outputs. [Rick]
  • Added block-usage to TagHelper#content_tag [DHH]. Example:
     <% content_tag :div, :class => "strong" %>
   Hello world!
 <% end %>

    Will output:

      <div class="strong">Hello world!</div>
  • Deprecated UrlHelper#link_to_image and UrlHelper#link_to :post => true 6409 [BobSilva]
  • Upgraded NumberHelper with number_to_phone support international formats to comply with ITU E.123 by supporting area codes with less than 3 digits, added precision argument to number_to_human_size (defaults to 1) 6421 [BobSilva]
  • Fixed that setting RAILS_ASSET_ID to "" should not add a trailing slash after assets 6454 [BobSilva/chrismear]
  • Force *_url named routes to show the host in ActionView [Rick]

    <%= url_for … %> # no host <%= foo_path %> # no host <%= foo_url %> # host!

  • Add support for converting blocks into function arguments to JavaScriptGenerator#call and JavaScriptProxy#call. [Sam Stephenson]
  • Add JavaScriptGenerator#literal for wrapping a string in an object whose to_json is the string itself. [Sam Stephenson]
  • Add <%= escape_once html %> to escape html while leaving any currently escaped entities alone. Fix button_to double-escaping issue. [Rick]
  • Fix double-escaped entities, such as &amp;amp;, &amp;123;, etc. [Rick]
  • Fix deprecation warnings when rendering the template error template. [Nicholas Seckar]
  • Fix routing to correctly determine when generation fails. Closes 6300. [psross].
  • Fix broken assert_generates when extra keys are being checked. [Jamis Buck]
  • Replace KCODE checks with String#chars for truncate. Closes 6385 [Manfred Stienstra]
  • Make page caching respect the format of the resource that is being requested even if the current route is the default route so that, e.g. posts.rss is not transformed by url_for to ’/’ and subsequently cached as ’/index.html’ when it should be cached as ’/posts.rss’. [Marcel Molina Jr.]
  • Use String#chars in TextHelper::excerpt. Closes 6386 [Manfred Stienstra]
  • Install named routes into ActionView::Base instead of proxying them to the view via helper_method. Closes 5932. [Nicholas Seckar]
  • Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
  • Fix relative URL root matching problems. [Mark Imbriaco]
  • Fix filter skipping in controller subclasses. 5949, 6297, 6299 [Martin Emde]
  • render_text may optionally append to the response body. render_javascript appends by default. This allows you to chain multiple render :update calls by setting @performed_render = false between them (awaiting a better public API). [Jeremy Kemper]
  • Rename test assertion to prevent shadowing. Closes 6306. [psross]
  • Fixed that NumberHelper#number_to_delimiter should respect precision of higher than two digits 6231 [phallstrom]
  • Fixed that FormHelper#radio_button didn‘t respect an :id being passed in 6266 [evansj]
  • Added an html_options hash parameter to javascript_tag() and update_page_tag() helpers 6311 [tzaharia]. Example:
      update_page_tag :defer => 'true' { |page| ... }

    Gives:

      <script defer="true" type="text/javascript">...</script>

    Which is needed for dealing with the IE6 DOM when it‘s not yet fully loaded.

  • Fixed that rescue template path shouldn‘t be hardcoded, then it‘s easier to hook in your own 6295 [mnaberez]
  • Fixed escaping of backslashes in JavaScriptHelper#escape_javascript 6302 [sven@c3d2.de]
  • Fixed that some 500 rescues would cause 500‘s themselves because the response had not yet been generated 6329 [cmselmer]
  • respond_to :html doesn‘t assume .rhtml. 6281 [Hampton Catlin]
  • Fixed some deprecation warnings in ActionPack [Rick Olson]
  • assert_select_rjs decodes escaped unicode chars since the Javascript generators encode them. 6240 [japgolly]
  • Deprecation: @cookies, @headers, @request, @response will be removed after 1.2. Use the corresponding method instead. [Jeremy Kemper]
  • Make the :status parameter expand to the default message for that status code if it is an integer. Also support symbol statuses. [Jamis Buck]. Examples:
      head :status => 404        # expands to "404 Not Found"
  head :status => :not_found # expands to "404 Not Found"
  head :status => :created   # expands to "201 Created"
  • Add head(options = {}) for responses that have no body. [Jamis Buck]. Examples:
      head :status => 404 # return an empty response with a 404 status
  head :location => person_path(@person), :status => 201
  • Fix bug that kept any before_filter except the first one from being able to halt the before_filter chain. [Rick Olson]
  • strip_links is case-insensitive. 6285 [tagoh, Bob Silva]
  • Clear the cache of possible controllers whenever Routes are reloaded. [Nicholas Seckar]
  • Filters overhaul including meantime filter support using around filters + blocks. 5949 [Martin Emde, Roman Le Negrate, Stefan Kaes, Jeremy Kemper]
  • Update RJS render tests. [sam]
  • Update CGI process to allow sessions to contain namespaced models. Closes 4638. [dfelstead@site5.com]
  • Fix routing to respect user provided requirements and defaults when assigning default routing options (such as :action => ‘index’). Closes 5950. [Nicholas Seckar]
  • Rescue Errno::ECONNRESET to handle an unexpectedly closed socket connection. Improves SCGI reliability. 3368, 6226 [sdsykes, fhanshaw@vesaria.com]
  • Added that respond_to blocks will automatically set the content type to be the same as is requested [DHH]. Examples:
      respond_to do |format|
    format.html { render :text => "I'm being sent as text/html" }
    format.rss  { render :text => "I'm being sent as application/rss+xml" }
    format.atom { render :text => "I'm being sent as application/xml", :content_type => Mime::XML }
  end
  • Added utf-8 as the default charset for all renders. You can change this default using ActionController::Base.default_charset=(encoding) [DHH]
  • Added proper getters and setters for content type and charset [DHH]. Example of what we used to do:
      response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"

    …now:

      response.content_type = Mime::ATOM
  response.charset      = "utf-8"
  • Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson]
    • XPATH support
    • Make Form.getElements() return elements in the correct order
    • fix broken Form.serialize return
  • Declare file extensions exempt from layouts. 6219 [brandon]
      Example: ActionController::Base.exempt_from_layout 'rpdf'
  • Add chained replace/update support for assert_select_rjs [Rick Olson]
      Given RJS like...

    page['test1'].replace "<div id=\"1\">foo</div>"
    page['test2'].replace_html "<div id=\"2\">foo</div>"

  Test it with...

    assert_select_rjs :chained_replace
    assert_select_rjs :chained_replace, "test1"

    assert_select_rjs :chained_replace_html
    assert_select_rjs :chained_replace_html, "test2"
  • Load helpers in alphabetical order for consistency. Resolve cyclic javascript_helper dependency. 6132, 6178 [choonkeat@gmail.com]
  • Skip params with empty names, such as the &=Save query string from <input type="submit"/>. 2569 [manfred, raphinou@yahoo.com]
  • Fix assert_tag so that :content => "foo" does not match substrings, but only exact strings. Use :content => /foo/ to match substrings. 2799 [Eric Hodel]
  • Add descriptive messages to the exceptions thrown by cgi_methods. 6091, 6103 [Nicholas Seckar, Bob Silva]
  • Update JavaScriptGenerator#show/hide/toggle/remove to new Prototype syntax for multiple ids, 6068 [petermichaux@gmail.com]
  • Update UrlWriter to support :only_path. [Nicholas Seckar, Dave Thomas]
  • Fixed JavaScriptHelper#link_to_function and JavaScriptHelper#button_to_function to have the script argument be optional [DHH]. So what used to require a nil, like this:
      link_to("Hider", nil, :class => "hider_link") { |p| p[:something].hide }

    …can be written like this:

      link_to("Hider", :class => "hider_link") { |p| p[:something].hide }
  • Update to script.aculo.us 1.6.3 [Thomas Fuchs]
  • Update to Prototype 1.5.0_rc1 [sam]
  • Added access to nested attributes in RJS 4548 [richcollins@gmail.com]. Examples:
      page['foo']['style']                  # => $('foo').style;
  page['foo']['style']['color']         # => $('blank_slate').style.color;
  page['foo']['style']['color'] = 'red' # => $('blank_slate').style.color = 'red';
  page['foo']['style'].color = 'red'    # => $('blank_slate').style.color = 'red';
  • Fixed that AssetTagHelper#image_tag and others using compute_public_path should not modify the incoming source argument (closes 5102) [eule@space.ch]
  • Deprecated the auto-appending of .png to AssetTagHelper#image_tag calls that doesn‘t have an extension [DHH]
  • Fixed FormOptionsHelper#select to respect :selected value 5813
  • Fixed TextHelper#simple_format to deal with multiple single returns within a single paragraph 5835 [moriq@moriq.com]
  • Fixed TextHelper#pluralize to handle 1 as a string 5909 [rails@bencurtis.com]
  • Improved resolution of DateHelper#distance_of_time_in_words for better precision 5994 [Bob Silva]
  • Changed that uncaught exceptions raised any where in the application will cause RAILS_ROOT/public/500.html to be read and shown instead of just the static "Application error (Rails)" [DHH]
  • Integration tests: thoroughly test ActionController::Integration::Session. 6022 [Kevin Clark]
      (tests skipped unless you `gem install mocha`)
  • Added deprecation language for pagination which will become a plugin by Rails 2.0 [DHH]
  • Added deprecation language for in_place_editor and auto_complete_field that both pieces will become plugins by Rails 2.0 [DHH]
  • Deprecated all of ActionController::Dependencies. All dependency loading is now handled from Active Support [DHH]
  • Added assert_select* for CSS selector-based testing (deprecates assert_tag) 5936 [assaf.arkin@gmail.com]
  • radio_button_tag generates unique id attributes. 3353 [Bob Silva, somekool@gmail.com]
  • strip_tags passes through blank args such as nil or "". 2229, 6702 [duncan@whomwah.com, dharana]
  • Cleanup assert_tag :children counting. 2181 [jamie@bravenet.com]
  • button_to accepts :method so you can PUT and DELETE with it. 6005 [Dan Webb]
  • Update sanitize text helper to strip plaintext tags, and <img src="javascript:bang">. [Rick Olson]
  • Update routing documentation. Closes 6017 [Nathan Witmer]
  • Add routing tests to assert that RoutingError is raised when conditions aren‘t met. Closes 6016 [Nathan Witmer]
  • Deprecation: update docs. 5998 [jakob@mentalized.net, Kevin Clark]
  • Make auto_link parse a greater subset of valid url formats. [Jamis Buck]
  • Integration tests: headers beginning with X aren‘t excluded from the HTTP_ prefix, so X-Requested-With becomes HTTP_X_REQUESTED_WITH as expected. [Mike Clark]
  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Fix send_data documentation typo. 5982 [brad@madriska.com]
  • Switch to using FormEncodedPairParser for parsing request parameters. [Nicholas Seckar, DHH]
  • respond_to .html now always renders #{action_name}.rhtml so that registered custom template handlers do not override it in priority. Custom mime types require a block and throw proper error now. [Tobias Luetke]
  • Deprecation: test deprecated instance vars in partials. [Jeremy Kemper]
  • Add UrlWriter to allow writing urls from Mailers and scripts. [Nicholas Seckar]
  • Clean up and run the Active Record integration tests by default. 5854 [kevin.clark@gmail.com, Jeremy Kemper]
  • Correct example in cookies docs. 5832 [jessemerriman@warpmail.net]
  • Updated to script.aculo.us 1.6.2 [Thomas Fuchs]
  • Relax Routing‘s anchor pattern warning; it was preventing use of [^/] inside restrictions. [Nicholas Seckar]
  • Add controller_paths variable to Routing. [Nicholas Seckar]
  • Fix assert_redirected_to issue with named routes for module controllers. [Rick Olson]
  • Tweak RoutingError message to show option diffs, not just missing named route significant keys. [Rick Olson]
  • Invoke method_missing directly on hidden actions. Closes 3030. [Nicholas Seckar]
  • Require Tempfile explicitly for TestUploadedFile due to changes in class auto loading. [Rick Olson]
  • Add RoutingError exception when RouteSet fails to generate a path from a Named Route. [Rick Olson]
  • Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
  • Deprecation: check whether instance variables have been monkeyed with before assigning them to deprecation proxies. Raises a RuntimeError if so. [Jeremy Kemper]
  • Add support for the param_name parameter to the auto_complete_field helper. 5026 [david.a.williams@gmail.com]
  • Deprecation! @params, @session, @flash will be removed after 1.2. Use the corresponding instance methods instead. You‘ll get printed warnings during tests and logged warnings in dev mode when you access either instance variable directly. [Jeremy Kemper]
  • Make Routing noisy when an anchor regexp is assigned to a segment. 5674 [francois.beausoleil@gmail.com]
  • Added months and years to the resolution of DateHelper#distance_of_time_in_words, such that "60 days ago" becomes "2 months ago" 5611 [pjhyett@gmail.com]
  • Short documentation to mention use of Mime::Type.register. 5710 [choonkeat@gmail.com]
  • Make controller_path available as an instance method. 5724 [jmckible@gmail.com]
  • Update query parser to support adjacent hashes. [Nicholas Seckar]
  • Make action caching aware of different formats for the same action so that, e.g. foo.xml is cached separately from foo.html. Implicitly set content type when reading in cached content with mime revealing extensions so the entire onous isn‘t on the webserver. [Marcel Molina Jr.]
  • Restrict Request Method hacking with ?_method to POST requests. [Rick Olson]
  • Fix bug when passing multiple options to SimplyRestful, like :new => { :preview => :get, :draft => :get }. [Rick Olson, Josh Susser, Lars Pind]
  • Dup the options passed to map.resources so that multiple resources get the same options. [Rick Olson]
  • Fixed the new_#{resource}_url route and added named route tests for Simply Restful. [Rick Olson]
  • Added map.resources from the Simply Restful plugin [DHH]. Examples (the API has changed to use plurals!):
      map.resources :messages
  map.resources :messages, :comments
  map.resources :messages, :new => { :preview => :post }
  • Fixed that integration simulation of XHRs should set Accept header as well [Edward Frederick]
  • TestRequest#reset_session should restore a TestSession, not a hash [Koz]
  • Don‘t search a load-path of ’.’ for controller files [Jamis Buck]
  • Update integration.rb to require test_process explicitly instead of via Dependencies. [Nicholas Seckar]
  • Fixed that you can still access the flash after the flash has been reset in reset_session. Closes 5584 [lmarlow@yahoo.com]
  • Allow form_for and fields_for to work with indexed form inputs. [Jeremy Kemper, Matt Lyon]

    <% form_for ‘post[]’, @post do |f| -%> <% end -%>

  • Remove leak in development mode by replacing define_method with module_eval. [Nicholas Seckar]
  • Provide support for decimal columns to form helpers. Closes 5672. [dave@pragprog.com]
  • Update documentation for erb trim syntax. 5651 [matt@mattmargolis.net]
  • Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. 3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
  • Reset @html_document between requests so assert_tag works. 4810 [jarkko@jlaine.net, easleydp@gmail.com]
  • Update render :partial documentation. 5646 [matt@mattmargolis.net]
  • Integration tests behave well with render_component. 4632 [edward.frederick@revolution.com, dev.rubyonrails@maxdunn.com]
  • Added exception handling of missing layouts 5373 [chris@ozmm.org]
  • Fixed that real files and symlinks should be treated the same when compiling templates 5438 [zachary@panandscan.com]
  • Fixed that the flash should be reset when reset_session is called 5584 [shugo@ruby-lang.org]
  • Added special case for "1 Byte" in NumberHelper#number_to_human_size 5593 [murpyh@rubychan.de]
  • Fixed proper form-encoded parameter parsing for requests with "Content-Type: application/x-www-form-urlencoded; charset=utf-8" (note the presence of a charset directive) [DHH]
  • Add route_name_path method to generate only the path for a named routes. For example, map.person will add person_path. [Nicholas Seckar]
  • Avoid naming collision among compiled view methods. [Jeremy Kemper]
  • Fix CGI extensions when they expect string but get nil in Windows. Closes 5276 [mislav@nippur.irb.hr]
  • Determine the correct template_root for deeply nested components. 2841 [s.brink@web.de]
  • Fix that routes with *path segments in the recall can generate URLs. [Rick]
  • Fix strip_links so that it doesn‘t hang on multiline <acronym> tags [Jamis Buck]
  • Remove problematic control chars in rescue template. 5316 [Stefan Kaes]
  • Make sure passed routing options are not mutated by routing code. 5314 [Blair Zajac]
  • Make sure changing the controller from foo/bar to bing/bang does not change relative to foo. [Jamis Buck]
  • Escape the path before routing recognition. 3671
  • Make sure :id and friends are unescaped properly. 5275 [me@julik.nl]
  • Fix documentation for with_routing to reflect new reality. 5281 [rramdas@gmail.com]
  • Rewind readable CGI params so others may reread them (such as CGI::Session when passing the session id in a multipart form). 210 [mklame@atxeu.com, matthew@walker.wattle.id.au]
  • Added Mime::TEXT (text/plain) and Mime::ICS (text/calendar) as new default types [DHH]
  • Added Mime::Type.register(string, symbol, synonyms = []) for adding new custom mime types [DHH]. Example: Mime::Type.register("image/gif", :gif)
  • Added support for Mime objects in render :content_type option [DHH]. Example: render :text => some_atom, :content_type => Mime::ATOM
  • Add :status option to send_data and send_file. Defaults to ‘200 OK’. 5243 [Manfred Stienstra <m.stienstra@fngtps.com>]
  • Routing rewrite. Simpler, faster, easier to understand. The published API for config/routes.rb is unchanged, but nearly everything else is different, so expect breakage in plugins and libs that try to fiddle with routes. [Nicholas Seckar, Jamis Buck]

    map.connect ’/foo/:id’, :controller => ’…’, :action => ’…’ map.connect ’/foo/:id.:format’, :controller => ’…’, :action => ’…’ map.connect ’/foo/:id’, …, :conditions => { :method => :get }

  • Cope with missing content type and length headers. Parse parameters from multipart and urlencoded request bodies only. [Jeremy Kemper]
  • Accept multipart PUT parameters. 5235 [guy.naor@famundo.com]
  • Added interrogation of params[:format] to determine Accept type. If :format is specified and matches a declared extension, like "rss" or "xml", that mime type will be put in front of the accept handler. This means you can link to the same action from different extensions and use that fact to determine output [DHH]. Example:

    class WeblogController < ActionController::Base

      def index
    @posts = Post.find :all

    respond_to do |format|
      format.html
      format.xml { render :xml => @posts.to_xml }
      format.rss { render :action => "feed.rxml" }
    end
  end

    end

    # returns HTML when requested by a browser, since the browser # has the HTML mimetype at the top of its priority list Accept: text/html GET /weblog

    # returns the XML Accept: application/xml GET /weblog

    # returns the HTML Accept: application/xml GET /weblog.html

    # returns the XML Accept: text/html GET /weblog.xml

    All this relies on the fact that you have a route that includes .:format.

  • Expanded :method option in FormTagHelper#form_tag, FormHelper#form_for, PrototypeHelper#remote_form_for, PrototypeHelper#remote_form_tag, and PrototypeHelper#link_to_remote to allow for verbs other than GET and POST by automatically creating a hidden form field named _method, which will simulate the other verbs over post [DHH]
  • Added :method option to UrlHelper#link_to, which allows for using other verbs than GET for the link. This replaces the :post option, which is now deprecated. Example: link_to "Destroy", person_url(:id => person), :method => :delete [DHH]
  • follow_redirect doesn‘t complain about being redirected to the same controller. 5153 [dymo@mk.ukrtelecom.ua]
  • Add layout attribute to response object with the name of the layout that was rendered, or nil if none rendered. [Kevin Clark kevin.clark@gmail.com]
  • Fix NoMethodError when parsing params like &&. [Adam Greenfield]
  • Fix flip flopped logic in docs for url_for‘s :only_path option. Closes 4998. [esad@esse.at]
  • form.text_area handles the :size option just like the original text_area (:size => ‘60x10’ becomes cols="60" rows="10"). [Jeremy Kemper]
  • Excise ingrown code from FormOptionsHelper#options_for_select. 5008 [anonymous]
  • Small fix in routing to allow dynamic routes (broken after [4242]) [Rick]
      map.connect '*path', :controller => 'files', :action => 'show'
  • Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Use flush between switching from write to syswrite. Closes 4907. [Blair Zajac <blair@orcaware.com>]
  • Documentation fix: integration test scripts don‘t require integration_test. Closes 4914. [Frederick Ros <sl33p3r@free.fr>]
  • ActionController::Base Summary documentation rewrite. Closes 4900. [kevin.clark@gmail.com]
  • Fix text_helper.rb documentation rendering. Closes 4725. [Frederick Ros]
  • Fixes bad rendering of JavaScriptMacrosHelper rdoc (closes 4910) [Frederick Ros]
  • Allow error_messages_for to report errors for multiple objects, as well as support for customizing the name of the object in the error summary header. Closes 4186. [andrew@redlinesoftware.com, Marcel Molina Jr.]

    error_messages_for :account, :user, :subscription, :object_name => :account

  • Enhance documentation for setting headers in integration tests. Skip auto HTTP prepending when its already there. Closes 4079. [Rick Olson]
  • Documentation for AbstractRequest. Closes 4895. [kevin.clark@gmail.com]
  • Refactor various InstanceTag instance method to class methods. Closes 4800. [skaes@web.de]
  • 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.]
  • Fix assert_redirected_to tests according to real-world usage. Also, don‘t fail if you add an extra :controller option: [Rick]
      redirect_to :action => 'new'
  assert_redirected_to :controller => 'monkeys', :action => 'new'
  • Cache CgiRequest#request_parameters so that multiple calls don‘t re-parse multipart data. [Rick]
  • Diff compared routing options. Allow assert_recognizes to take a second arg as a hash to specify optional request method [Rick]
      assert_recognizes({:controller => 'users', :action => 'index'}, 'users')
  assert_recognizes({:controller => 'users', :action => 'create'}, {:path => 'users', :method => :post})
  • Diff compared options with assert_redirected_to [Rick]
  • Add support in routes for semicolon delimited "subpaths", like /books/:id;:action [Jamis Buck]
  • Change link_to_function and button_to_function to (optionally) take an update_page block instead of a JavaScript string. Closes 4804. [zraii@comcast.net, Sam Stephenson]
  • 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]
  • Modify routing so that you can say :require => { :method => :post } for a route, and the route will never be selected unless the request method is POST. Only works for route recognition, not for route generation. [Jamis Buck]
  • Added :add_headers option to verify which merges a hash of name/value pairs into the response‘s headers hash if the prerequisites cannot be satisfied. [Sam Stephenson] ex. verify :only => :speak, :method => :post,
               :render => { :status => 405, :text => "Must be post" },
           :add_headers => { "Allow" => "POST" }
  • 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]

*1.13.3* (March 12th, 2007)

  • Apply [5709] to stable.
  • session_enabled? works with session :off. 6680 [Catfish]
  • Performance: patch cgi/session to require digest/md5 once rather than per create_new_id. [Stefan Kaes]

*1.13.2* (February 5th, 2007)

  • Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
  • improve error message for Routing for named routes. [Rob Sanheim]
  • Added enhanced docs to routing assertions. [Rob Sanheim]
  • fix form_for example in ActionController::Resources documentation. [gnarg]
  • Add singleton resources from trunk [Rick Olson]
  • select :multiple => true suffixes the attribute name with [] unless already suffixed. 6977 [nik.kakelin, ben, julik]
  • Improve routes documentation. 7095 [zackchandler]
  • Resource member routes require :id, eliminating the ambiguous overlap with collection routes. 7229 [dkubb]
  • Fixed NumberHelper#number_with_delimiter to use "." always for splitting the original number, not the delimiter parameter 7389 [ceefour]
  • Autolinking recognizes trailing and embedded . , : ; 7354 [Jarkko Laine]
  • Make TextHelper::auto_link recognize URLs with colons in path correctly, fixes 7268. [imajes]
  • Improved auto_link to match more valid urls correctly [Tobias Luetke]

*1.13.1* (January 18th, 2007)

  • Fixed content-type bug in Prototype [sam]

*1.13.0* (January 16th, 2007)

  • Modernize cookie testing code, and increase coverage (Heckle++) 7101 [Kevin Clark]
  • Heckling ActionController::Resources::Resource revealed that set_prefixes didn‘t break when :name_prefix was munged. 7081 [Kevin Clark]
  • Update to Prototype 1.5.0. [Sam Stephenson]
  • Allow exempt_from_layout :rhtml. 6742, 7026 [dcmanges, Squeegy]
  • Fix parsing of array[] CGI parameters so extra empty values aren‘t included. 6252 [Nicholas Seckar, aiwilliams, brentrowland]
  • link_to_unless_current works with full URLs as well as paths. 6891 [Jarkko Laine, manfred, idrifter]
  • Fix HTML::Node to output double quotes instead of single quotes. Closes 6845 [mitreandy]
  • Fix no method error with error_messages_on. Closes 6935 [nik.wakelin Koz]
  • Slight doc tweak to the ActionView::Helpers::PrototypeHelper#replace docs. Closes 6922 [Steven Bristol]
  • Slight doc tweak to prepend_filter. Closes 6493 [Jeremy Voorhis]
  • Add more extensive documentation to the AssetTagHelper. Closes 6452 [Bob Silva]
  • Clean up multiple calls to stringify_keys in TagHelper, add better documentation and testing for TagHelper. Closes 6394 [Bob Silva]
  • [DOCS] fix reference to ActionController::Macros::AutoComplete for text_field_with_auto_complete. Closes 2578 [Jan Prill]
  • Make sure html_document is reset between integration test requests. [ctm]
  • Set session to an empty hash if :new_session => false and no session cookie or param is present. CGI::Session was raising an unrescued ArgumentError. [Josh Susser]
  • Fix assert_redirected_to bug where redirecting from a nested to to a top-level controller incorrectly added the current controller‘s nesting. Closes 6128. [Rick Olson]
  • Ensure render :json => … skips the layout. 6808 [Josh Peek]
  • Silence log_error deprecation warnings from inspecting deprecated instance variables. [Nate Wiger]
  • Only cache GET requests with a 200 OK response. 6514, 6743 [RSL, anamba]
  • Correctly report which filter halted the chain. 6699 [Martin Emde]
  • respond_to recognizes JSON. render :json => @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. 4185 [Scott Raymond, eventualbuddha]
      # application/json response with body 'Element.show({:name: "David"})'
  respond_to do |format|
    format.json { render :json => { :name => "David" }.to_json, :callback => 'Element.show' }
  end
  • Makes :discard_year work without breaking multi-attribute parsing in AR. 1260, 3800 [sean@ardismg.com, jmartin@desertflood.com, stephen@touset.org, Bob Silva]
  • Adds html id attribute to date helper elements. 1050, 1382 [mortonda@dgrmm.net, David North, Bob Silva]
  • Add :index and @auto_index capability to model driven date/time selects. 847, 2655 [moriq, Doug Fales, Bob Silva]
  • Add :order to datetime_select, select_datetime, and select_date. 1427 [Timothee Peignier, patrick@lenz.sh, Bob Silva]
  • Added time_select to work with time values in models. Update scaffolding. 2489, 2833 [Justin Palmer, Andre Caum, Bob Silva]
  • Added :include_seconds to select_datetime, datetime_select and time_select. 2998 [csn, Bob Silva]
  • All date/datetime selects can now accept an array of month names with :use_month_names. Allows for localization. 363 [tomasj, Bob Silva]
  • Adds :time_separator to select_time and :date_separator to select_datetime. Preserves BC. 3811 [Bob Silva]
  • @response.redirect_url works with 201 Created responses: just return headers[‘Location’] rather than checking the response status. [Jeremy Kemper]
  • Fixed that HEAD should return the proper Content-Length header (that is, actually use @body.size, not just 0) [DHH]
  • Added GET-masquarading for HEAD, so request.method will return :get even for HEADs. This will help anyone relying on case request.method to automatically work with HEAD and map.resources will also allow HEADs to all GET actions. Rails automatically throws away the response content in a reply to HEAD, so you don‘t even need to worry about that. If you, for whatever reason, still need to distinguish between GET and HEAD in some edge case, you can use Request#head? and even Request.headers["REQUEST_METHOD"] for get the "real" answer. Closes 6694 [DHH]

*1.13.0 RC1* (r5619, November 22nd, 2006)

  • Update Routing to complain when :controller is not specified by a route. Closes 6669. [Nicholas Seckar]
  • Ensure render_to_string cleans up after itself when an exception is raised. 6658 [rsanheim]
  • Update to Prototype and script.aculo.us [5579]. [Sam Stephenson, Thomas Fuchs]
  • simple_format helper doesn‘t choke on nil. 6644 [jerry426]
  • Reuse named route helper module between Routing reloads. Use remove_method to delete named route methods after each load. Since the module is never collected, this fixes a significant memory leak. [Nicholas Seckar]
  • Deprecate standalone components. [Jeremy Kemper]
  • Always clear model associations from session. 4795 [sd@notso.net, andylien@gmail.com]
  • Remove JavaScriptLiteral in favor of ActiveSupport::JSON::Variable. [Sam Stephenson]
  • Sync ActionController::StatusCodes::STATUS_CODES with www.iana.org/assignments/http-status-codes. 6586 [dkubb]
  • Multipart form values may have a content type without being treated as uploaded files if they do not provide a filename. 6401 [Andreas Schwarz, Jeremy Kemper]
  • assert_response supports symbolic status codes. 6569 [Kevin Clark]
      assert_response :ok
  assert_response :not_found
  assert_response :forbidden
  • Cache parsed query parameters. 6559 [Stefan Kaes]
  • Deprecate JavaScriptHelper#update_element_function, which is superseeded by RJS [Thomas Fuchs]
  • Fix invalid test fixture exposed by stricter Ruby 1.8.5 multipart parsing. 6524 [Bob Silva]
  • Set ActionView::Base.default_form_builder once rather than passing the :builder option to every form or overriding the form helper methods. [Jeremy Kemper]
  • Deprecate expire_matched_fragments. Use expire_fragment instead. 6535 [Bob Silva]
  • Deprecate start_form_tag and end_form_tag. Use form_tag / ’</form>’ from now on. [Rick]
  • Added block-usage to PrototypeHelper#form_remote_tag, document block-usage of FormTagHelper#form_tag [Rick]
  • Add a 0 margin/padding div around the hidden _method input tag that form_tag outputs. [Rick]
  • Added block-usage to TagHelper#content_tag [DHH]. Example:
     <% content_tag :div, :class => "strong" %>
   Hello world!
 <% end %>

    Will output:

      <div class="strong">Hello world!</div>
  • Deprecated UrlHelper#link_to_image and UrlHelper#link_to :post => true 6409 [BobSilva]
  • Upgraded NumberHelper with number_to_phone support international formats to comply with ITU E.123 by supporting area codes with less than 3 digits, added precision argument to number_to_human_size (defaults to 1) 6421 [BobSilva]
  • Fixed that setting RAILS_ASSET_ID to "" should not add a trailing slash after assets 6454 [BobSilva/chrismear]
  • Force *_url named routes to show the host in ActionView [Rick]

    <%= url_for … %> # no host <%= foo_path %> # no host <%= foo_url %> # host!

  • Add support for converting blocks into function arguments to JavaScriptGenerator#call and JavaScriptProxy#call. [Sam Stephenson]
  • Add JavaScriptGenerator#literal for wrapping a string in an object whose to_json is the string itself. [Sam Stephenson]
  • Add <%= escape_once html %> to escape html while leaving any currently escaped entities alone. Fix button_to double-escaping issue. [Rick]
  • Fix double-escaped entities, such as &amp;amp;, &amp;123;, etc. [Rick]
  • Fix routing to correctly determine when generation fails. Closes 6300. [psross].
  • Fix broken assert_generates when extra keys are being checked. [Jamis Buck]
  • Replace KCODE checks with String#chars for truncate. Closes 6385 [Manfred Stienstra]
  • Make page caching respect the format of the resource that is being requested even if the current route is the default route so that, e.g. posts.rss is not transformed by url_for to ’/’ and subsequently cached as ’/index.html’ when it should be cached as ’/posts.rss’. [Marcel Molina Jr.]
  • Use String#chars in TextHelper::excerpt. Closes 6386 [Manfred Stienstra]
  • Fix relative URL root matching problems. [Mark Imbriaco]
  • Fix filter skipping in controller subclasses. 5949, 6297, 6299 [Martin Emde]
  • render_text may optionally append to the response body. render_javascript appends by default. This allows you to chain multiple render :update calls by setting @performed_render = false between them (awaiting a better public API). [Jeremy Kemper]
  • Rename test assertion to prevent shadowing. Closes 6306. [psross]
  • Fixed that NumberHelper#number_to_delimiter should respect precision of higher than two digits 6231 [phallstrom]
  • Fixed that FormHelper#radio_button didn‘t respect an :id being passed in 6266 [evansj]
  • Added an html_options hash parameter to javascript_tag() and update_page_tag() helpers 6311 [tzaharia]. Example:
      update_page_tag :defer => 'true' { |page| ... }

    Gives:

      <script defer="true" type="text/javascript">...</script>

    Which is needed for dealing with the IE6 DOM when it‘s not yet fully loaded.

  • Fixed that rescue template path shouldn‘t be hardcoded, then it‘s easier to hook in your own 6295 [mnaberez]
  • Fixed escaping of backslashes in JavaScriptHelper#escape_javascript 6302 [sven@c3d2.de]
  • Fixed that some 500 rescues would cause 500‘s themselves because the response had not yet been generated 6329 [cmselmer]
  • respond_to :html doesn‘t assume .rhtml. 6281 [Hampton Catlin]
  • Fixed some deprecation warnings in ActionPack [Rick Olson]
  • assert_select_rjs decodes escaped unicode chars since the Javascript generators encode them. 6240 [japgolly]
  • Deprecation: @cookies, @headers, @request, @response will be removed after 1.2. Use the corresponding method instead. [Jeremy Kemper]
  • Make the :status parameter expand to the default message for that status code if it is an integer. Also support symbol statuses. [Jamis Buck]. Examples:
      head :status => 404        # expands to "404 Not Found"
  head :status => :not_found # expands to "404 Not Found"
  head :status => :created   # expands to "201 Created"
  • Add head(options = {}) for responses that have no body. [Jamis Buck]. Examples:
      head :status => 404 # return an empty response with a 404 status
  head :location => person_path(@person), :status => 201
  • Fix bug that kept any before_filter except the first one from being able to halt the before_filter chain. [Rick Olson]
  • strip_links is case-insensitive. 6285 [tagoh, Bob Silva]
  • Clear the cache of possible controllers whenever Routes are reloaded. [Nicholas Seckar]
  • Filters overhaul including meantime filter support using around filters + blocks. 5949 [Martin Emde, Roman Le Negrate, Stefan Kaes, Jeremy Kemper]
  • Update CGI process to allow sessions to contain namespaced models. Closes 4638. [dfelstead@site5.com]
  • Fix routing to respect user provided requirements and defaults when assigning default routing options (such as :action => ‘index’). Closes 5950. [Nicholas Seckar]
  • Rescue Errno::ECONNRESET to handle an unexpectedly closed socket connection. Improves SCGI reliability. 3368, 6226 [sdsykes, fhanshaw@vesaria.com]
  • Added that respond_to blocks will automatically set the content type to be the same as is requested [DHH]. Examples:
      respond_to do |format|
    format.html { render :text => "I'm being sent as text/html" }
    format.rss  { render :text => "I'm being sent as application/rss+xml" }
    format.atom { render :text => "I'm being sent as application/xml", :content_type => Mime::XML }
  end
  • Added utf-8 as the default charset for all renders. You can change this default using ActionController::Base.default_charset=(encoding) [DHH]
  • Added proper getters and setters for content type and charset [DHH]. Example of what we used to do:
      response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"

    …now:

      response.content_type = Mime::ATOM
  response.charset      = "utf-8"
  • Declare file extensions exempt from layouts. 6219 [brandon]
      Example: ActionController::Base.exempt_from_layout 'rpdf'
  • Add chained replace/update support for assert_select_rjs [Rick Olson]
      Given RJS like...

    page['test1'].replace "<div id=\"1\">foo</div>"
    page['test2'].replace_html "<div id=\"2\">foo</div>"

  Test it with...

    assert_select_rjs :chained_replace
    assert_select_rjs :chained_replace, "test1"

    assert_select_rjs :chained_replace_html
    assert_select_rjs :chained_replace_html, "test2"
  • Load helpers in alphabetical order for consistency. Resolve cyclic javascript_helper dependency. 6132, 6178 [choonkeat@gmail.com]
  • Skip params with empty names, such as the &=Save query string from <input type="submit"/>. 2569 [manfred, raphinou@yahoo.com]
  • Fix assert_tag so that :content => "foo" does not match substrings, but only exact strings. Use :content => /foo/ to match substrings. 2799 [Eric Hodel]
  • Update JavaScriptGenerator#show/hide/toggle/remove to new Prototype syntax for multiple ids, 6068 [petermichaux@gmail.com]
  • Update UrlWriter to support :only_path. [Nicholas Seckar, Dave Thomas]
  • Fixed JavaScriptHelper#link_to_function and JavaScriptHelper#button_to_function to have the script argument be optional [DHH]. So what used to require a nil, like this:
      link_to("Hider", nil, :class => "hider_link") { |p| p[:something].hide }

    …can be written like this:

      link_to("Hider", :class => "hider_link") { |p| p[:something].hide }
  • Added access to nested attributes in RJS 4548 [richcollins@gmail.com]. Examples:
      page['foo']['style']                  # => $('foo').style;
  page['foo']['style']['color']         # => $('blank_slate').style.color;
  page['foo']['style']['color'] = 'red' # => $('blank_slate').style.color = 'red';
  page['foo']['style'].color = 'red'    # => $('blank_slate').style.color = 'red';
  • Fixed that AssetTagHelper#image_tag and others using compute_public_path should not modify the incoming source argument (closes 5102) [eule@space.ch]
  • Deprecated the auto-appending of .png to AssetTagHelper#image_tag calls that doesn‘t have an extension [DHH]
  • Fixed FormOptionsHelper#select to respect :selected value 5813
  • Fixed TextHelper#simple_format to deal with multiple single returns within a single paragraph 5835 [moriq@moriq.com]
  • Fixed TextHelper#pluralize to handle 1 as a string 5909 [rails@bencurtis.com]
  • Improved resolution of DateHelper#distance_of_time_in_words for better precision 5994 [Bob Silva]
  • Changed that uncaught exceptions raised any where in the application will cause RAILS_ROOT/public/500.html to be read and shown instead of just the static "Application error (Rails)" [DHH]
  • Added deprecation language for pagination which will become a plugin by Rails 2.0 [DHH]
  • Added deprecation language for in_place_editor and auto_complete_field that both pieces will become plugins by Rails 2.0 [DHH]
  • Deprecated all of ActionController::Dependencies. All dependency loading is now handled from Active Support [DHH]
  • Added assert_select* for CSS selector-based testing (deprecates assert_tag) 5936 [assaf.arkin@gmail.com]
  • radio_button_tag generates unique id attributes. 3353 [Bob Silva, somekool@gmail.com]
  • strip_tags passes through blank args such as nil or "". 2229, 6702 [duncan@whomwah.com, dharana]
  • Cleanup assert_tag :children counting. 2181 [jamie@bravenet.com]
  • button_to accepts :method so you can PUT and DELETE with it. 6005 [Dan Webb]
  • Update sanitize text helper to strip plaintext tags, and <img src="javascript:bang">. [Rick Olson]
  • Add routing tests to assert that RoutingError is raised when conditions aren‘t met. Closes 6016 [Nathan Witmer]
  • Make auto_link parse a greater subset of valid url formats. [Jamis Buck]
  • Integration tests: headers beginning with X aren‘t excluded from the HTTP_ prefix, so X-Requested-With becomes HTTP_X_REQUESTED_WITH as expected. [Mike Clark]
  • Switch to using FormEncodedPairParser for parsing request parameters. [Nicholas Seckar, DHH]
  • respond_to .html now always renders #{action_name}.rhtml so that registered custom template handlers do not override it in priority. Custom mime types require a block and throw proper error now. [Tobias Luetke]
  • Deprecation: test deprecated instance vars in partials. [Jeremy Kemper]
  • Add UrlWriter to allow writing urls from Mailers and scripts. [Nicholas Seckar]
  • Relax Routing‘s anchor pattern warning; it was preventing use of [^/] inside restrictions. [Nicholas Seckar]
  • Add controller_paths variable to Routing. [Nicholas Seckar]
  • Fix assert_redirected_to issue with named routes for module controllers. [Rick Olson]
  • Tweak RoutingError message to show option diffs, not just missing named route significant keys. [Rick Olson]
  • Invoke method_missing directly on hidden actions. Closes 3030. [Nicholas Seckar]
  • Add RoutingError exception when RouteSet fails to generate a path from a Named Route. [Rick Olson]
  • Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
  • Deprecation: check whether instance variables have been monkeyed with before assigning them to deprecation proxies. Raises a RuntimeError if so. [Jeremy Kemper]
  • Add support for the param_name parameter to the auto_complete_field helper. 5026 [david.a.williams@gmail.com]
  • Deprecation! @params, @session, @flash will be removed after 1.2. Use the corresponding instance methods instead. You‘ll get printed warnings during tests and logged warnings in dev mode when you access either instance variable directly. [Jeremy Kemper]
  • Make Routing noisy when an anchor regexp is assigned to a segment. 5674 [francois.beausoleil@gmail.com]
  • Added months and years to the resolution of DateHelper#distance_of_time_in_words, such that "60 days ago" becomes "2 months ago" 5611 [pjhyett@gmail.com]
  • Make controller_path available as an instance method. 5724 [jmckible@gmail.com]
  • Update query parser to support adjacent hashes. [Nicholas Seckar]
  • Make action caching aware of different formats for the same action so that, e.g. foo.xml is cached separately from foo.html. Implicitly set content type when reading in cached content with mime revealing extensions so the entire onous isn‘t on the webserver. [Marcel Molina Jr.]
  • Restrict Request Method hacking with ?_method to POST requests. [Rick Olson]
  • Fixed the new_#{resource}_url route and added named route tests for Simply Restful. [Rick Olson]
  • Added map.resources from the Simply Restful plugin [DHH]. Examples (the API has changed to use plurals!):
      map.resources :messages
  map.resources :messages, :comments
  map.resources :messages, :new => { :preview => :post }
  • Fixed that integration simulation of XHRs should set Accept header as well [Edward Frederick]
  • TestRequest#reset_session should restore a TestSession, not a hash [Koz]
  • Don‘t search a load-path of ’.’ for controller files [Jamis Buck]
  • Update integration.rb to require test_process explicitly instead of via Dependencies. [Nicholas Seckar]
  • Fixed that you can still access the flash after the flash has been reset in reset_session. Closes 5584 [lmarlow@yahoo.com]
  • Allow form_for and fields_for to work with indexed form inputs. [Jeremy Kemper, Matt Lyon]

    <% form_for ‘post[]’, @post do |f| -%> <% end -%>

  • Remove leak in development mode by replacing define_method with module_eval. [Nicholas Seckar]
  • Provide support for decimal columns to form helpers. Closes 5672. [dave@pragprog.com]
  • Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. 3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
  • Reset @html_document between requests so assert_tag works. 4810 [jarkko@jlaine.net, easleydp@gmail.com]
  • Integration tests behave well with render_component. 4632 [edward.frederick@revolution.com, dev.rubyonrails@maxdunn.com]
  • Added exception handling of missing layouts 5373 [chris@ozmm.org]
  • Fixed that real files and symlinks should be treated the same when compiling templates 5438 [zachary@panandscan.com]
  • Fixed that the flash should be reset when reset_session is called 5584 [shugo@ruby-lang.org]
  • Added special case for "1 Byte" in NumberHelper#number_to_human_size 5593 [murpyh@rubychan.de]
  • Fixed proper form-encoded parameter parsing for requests with "Content-Type: application/x-www-form-urlencoded; charset=utf-8" (note the presence of a charset directive) [DHH]
  • Add route_name_path method to generate only the path for a named routes. For example, map.person will add person_path. [Nicholas Seckar]
  • Avoid naming collision among compiled view methods. [Jeremy Kemper]
  • Fix CGI extensions when they expect string but get nil in Windows. Closes 5276 [mislav@nippur.irb.hr]
  • Determine the correct template_root for deeply nested components. 2841 [s.brink@web.de]
  • Fix that routes with *path segments in the recall can generate URLs. [Rick]
  • Fix strip_links so that it doesn‘t hang on multiline <acronym> tags [Jamis Buck]
  • Remove problematic control chars in rescue template. 5316 [Stefan Kaes]
  • Make sure passed routing options are not mutated by routing code. 5314 [Blair Zajac]
  • Make sure changing the controller from foo/bar to bing/bang does not change relative to foo. [Jamis Buck]
  • Escape the path before routing recognition. 3671
  • Make sure :id and friends are unescaped properly. 5275 [me@julik.nl]
  • Rewind readable CGI params so others may reread them (such as CGI::Session when passing the session id in a multipart form). 210 [mklame@atxeu.com, matthew@walker.wattle.id.au]
  • Added Mime::TEXT (text/plain) and Mime::ICS (text/calendar) as new default types [DHH]
  • Added Mime::Type.register(string, symbol, synonyms = []) for adding new custom mime types [DHH]. Example: Mime::Type.register("image/gif", :gif)
  • Added support for Mime objects in render :content_type option [DHH]. Example: render :text => some_atom, :content_type => Mime::ATOM
  • Add :status option to send_data and send_file. Defaults to ‘200 OK’. 5243 [Manfred Stienstra <m.stienstra@fngtps.com>]
  • Routing rewrite. Simpler, faster, easier to understand. The published API for config/routes.rb is unchanged, but nearly everything else is different, so expect breakage in plugins and libs that try to fiddle with routes. [Nicholas Seckar, Jamis Buck]

    map.connect ’/foo/:id’, :controller => ’…’, :action => ’…’ map.connect ’/foo/:id.:format’, :controller => ’…’, :action => ’…’ map.connect ’/foo/:id’, …, :conditions => { :method => :get }

  • Cope with missing content type and length headers. Parse parameters from multipart and urlencoded request bodies only. [Jeremy Kemper]
  • Accept multipart PUT parameters. 5235 [guy.naor@famundo.com]
  • Added interrogation of params[:format] to determine Accept type. If :format is specified and matches a declared extension, like "rss" or "xml", that mime type will be put in front of the accept handler. This means you can link to the same action from different extensions and use that fact to determine output [DHH]. Example:

    class WeblogController < ActionController::Base

      def index
    @posts = Post.find :all

    respond_to do |format|
      format.html
      format.xml { render :xml => @posts.to_xml }
      format.rss { render :action => "feed.rxml" }
    end
  end

    end

    # returns HTML when requested by a browser, since the browser # has the HTML mimetype at the top of its priority list Accept: text/html GET /weblog

    # returns the XML Accept: application/xml GET /weblog

    # returns the HTML Accept: application/xml GET /weblog.html

    # returns the XML Accept: text/html GET /weblog.xml

    All this relies on the fact that you have a route that includes .:format.

  • Expanded :method option in FormTagHelper#form_tag, FormHelper#form_for, PrototypeHelper#remote_form_for, PrototypeHelper#remote_form_tag, and PrototypeHelper#link_to_remote to allow for verbs other than GET and POST by automatically creating a hidden form field named _method, which will simulate the other verbs over post [DHH]
  • Added :method option to UrlHelper#link_to, which allows for using other verbs than GET for the link. This replaces the :post option, which is now deprecated. Example: link_to "Destroy", person_url(:id => person), :method => :delete [DHH]
  • follow_redirect doesn‘t complain about being redirected to the same controller. 5153 [dymo@mk.ukrtelecom.ua]
  • Add layout attribute to response object with the name of the layout that was rendered, or nil if none rendered. [Kevin Clark kevin.clark@gmail.com]
  • Fix NoMethodError when parsing params like &&. [Adam Greenfield]
  • form.text_area handles the :size option just like the original text_area (:size => ‘60x10’ becomes cols="60" rows="10"). [Jeremy Kemper]
  • Excise ingrown code from FormOptionsHelper#options_for_select. 5008 [anonymous]
  • Small fix in routing to allow dynamic routes (broken after [4242]) [Rick]
      map.connect '*path', :controller => 'files', :action => 'show'
  • Use flush between switching from write to syswrite. Closes 4907. [Blair Zajac <blair@orcaware.com>]
  • Allow error_messages_for to report errors for multiple objects, as well as support for customizing the name of the object in the error summary header. Closes 4186. [andrew@redlinesoftware.com, Marcel Molina Jr.]

    error_messages_for :account, :user, :subscription, :object_name => :account

  • Fix assert_redirected_to tests according to real-world usage. Also, don‘t fail if you add an extra :controller option: [Rick]
      redirect_to :action => 'new'
  assert_redirected_to :controller => 'monkeys', :action => 'new'
  • Diff compared routing options. Allow assert_recognizes to take a second arg as a hash to specify optional request method [Rick]
      assert_recognizes({:controller => 'users', :action => 'index'}, 'users')
  assert_recognizes({:controller => 'users', :action => 'create'}, {:path => 'users', :method => :post})
  • Diff compared options with assert_redirected_to [Rick]
  • Add support in routes for semicolon delimited "subpaths", like /books/:id;:action [Jamis Buck]
  • Change link_to_function and button_to_function to (optionally) take an update_page block instead of a JavaScript string. Closes 4804. [zraii@comcast.net, Sam Stephenson]
  • Modify routing so that you can say :require => { :method => :post } for a route, and the route will never be selected unless the request method is POST. Only works for route recognition, not for route generation. [Jamis Buck]
  • Added :add_headers option to verify which merges a hash of name/value pairs into the response‘s headers hash if the prerequisites cannot be satisfied. [Sam Stephenson] ex. verify :only => :speak, :method => :post,
               :render => { :status => 405, :text => "Must be post" },
           :add_headers => { "Allow" => "POST" }

*1.12.5* (August 10th, 2006)

  • Updated security fix

*1.12.4* (August 8th, 2006)

  • 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]
  • Update to Prototype 1.5.0_rc0 [Sam Stephenson]
  • Honor skipping filters conditionally for only certain actions even when the parent class sets that filter to conditionally be executed only for the same actions. 4522 [Marcel Molina Jr.]
  • Delegate xml_http_request in integration tests to the session instance. [Jamis Buck]
  • Update the diagnostics template skip the useless ’<controller not set>’ text. [Nicholas Seckar]
  • CHANGED DEFAULT: Don‘t parse YAML input by default, but keep it available as an easy option [DHH]
  • Add additional autocompleter options [aballai, Thomas Fuchs]
  • Fixed fragment caching of binary data on Windows 4493 [bellis@deepthought.org]
  • Applied Prototype $() performance patches (4465, 4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
  • Added automated timestamping to AssetTagHelper methods for stylesheets, javascripts, and images when Action Controller is run under Rails [DHH]. Example:
      image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?1143664135" />'

    …to avoid frequent stats (not a problem for most people), you can set RAILS_ASSET_ID in the ENV to avoid stats:

      ENV["RAILS_ASSET_ID"] = "2345"
  image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?2345" />'

    This can be used by deployment managers to set the asset id by application revision

*1.12.0* (March 27th, 2006)

  • Add documentation for respond_to. [Jamis Buck]
  • Fixed require of bluecloth and redcloth when gems haven‘t been loaded 4446 [murphy@cYcnus.de]
  • Update to Prototype 1.5.0_pre1 [Sam Stephenson]
  • Change form_for and fields_for so that the second argument is not required [Dave Thomas]
      <% form_for :post, @post, :url => { :action => 'create' } do |f| -%>

    becomes…

      <% form_for :post, :url => { :action => 'create' } do |f| -%>
  • Update to script.aculo.us 1.6 [Thomas Fuchs]
  • Enable application/x-yaml processing by default [Jamis Buck]
  • Fix double url escaping of remote_function. Add :escape => false option to ActionView‘s url_for. [Nicholas Seckar]
  • Add :script option to in_place_editor to support evalScripts (closes 4194) [codyfauser@gmail.com]
  • Fix mixed case enumerable methods in the JavaScript Collection Proxy (closes 4314) [codyfauser@gmail.com]
  • Undo accidental escaping for mail_to; add regression test. [Nicholas Seckar]
  • Added nicer message for assert_redirected_to (closes 4294) [court3nay]
      assert_redirected_to :action => 'other_host', :only_path => false

    when it was expecting…

      redirected_to :action => 'other_host', :only_path => true, :host => 'other.test.host'

    gives the error message…

      response is not a redirection to all of the options supplied (redirection is <{:only_path=>false, :host=>"other.test.host", :action=>"other_host"}>), difference: <{:only_path=>"true", :host=>"other.test.host"}>
  • Change url_for to escape the resulting URLs when called from a view. [Nicholas Seckar, coffee2code]
  • Added easy support for testing file uploads with fixture_file_upload 4105 [turnip@turnipspatch.com]. Example:
      # Looks in Test::Unit::TestCase.fixture_path + '/files/spongebob.png'
  post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
  • Fixed UrlHelper#current_page? to behave even when url-escaped entities are present 3929 [jeremy@planetargon.com]
  • Add ability for relative_url_root to be specified via an environment variable RAILS_RELATIVE_URL_ROOT. [isaac@reuben.com, Nicholas Seckar]
  • Fixed link_to "somewhere", :post => true to produce valid XHTML by using the parentnode instead of document.body for the instant form 3007 [Bob Silva]
  • Added :function option to PrototypeHelper#observe_field/observe_form that allows you to call a function instead of submitting an ajax call as the trigger 4268 [jonathan@daikini.com]
  • Make Mime::Type.parse consider q values (if any) [Jamis Buck]
  • XML-formatted requests are typecast according to "type" attributes for :xml_simple [Jamis Buck]
  • Added protection against proxy setups treating requests as local even when they‘re not 3898 [stephen_purcell@yahoo.com]
  • Added TestRequest#raw_post that simulate raw_post from CgiRequest 3042 [francois.beausoleil@gmail.com]
  • Underscore dasherized keys in formatted requests [Jamis Buck]
  • Add MimeResponds::Responder#any for managing multiple types with identical responses [Jamis Buck]
  • Make the xml_http_request testing method set the HTTP_ACCEPT header [Jamis Buck]
  • Add Verification to scaffolds. Prevent destructive actions using GET [Michael Koziarski]
  • Avoid hitting the filesystem when using layouts by using a File.directory? cache. [Stefan Kaes, Nicholas Seckar]
  • Simplify ActionController::Base#controller_path [Nicholas Seckar]
  • Added simple alert() notifications for RJS exceptions when config.action_view.debug_rjs = true. [Sam Stephenson]
  • Added :content_type option to render, so you can change the content type on the fly [DHH]. Example: render :action => "atom.rxml", :content_type => "application/atom+xml"
  • CHANGED DEFAULT: The default content type for .rxml is now application/xml instead of type/xml, see www.xml.com/pub/a/2004/07/21/dive.html for reason [DHH]
  • Added option to render action/template/file of a specific extension (and here by template type). This means you can have multiple templates with the same name but a different extension [DHH]. Example:
      class WeblogController < ActionController::Base
    def index
      @posts = Post.find :all

      respond_to do |type|
        type.html # using defaults, which will render weblog/index.rhtml
        type.xml  { render :action => "index.rxml" }
        type.js   { render :action => "index.rjs" }
      end
    end
  end
  • Added better support for using the same actions to output for different sources depending on the Accept header [DHH]. Example:
      class WeblogController < ActionController::Base
    def create
      @post = Post.create(params[:post])

      respond_to do |type|
        type.js   { render }  # renders create.rjs
        type.html { redirect_to :action => "index" }
        type.xml  do
          headers["Location"] = url_for(:action => "show", :id => @post)
          render(:nothing, :status => "201 Created")
        end
      end
    end
  end
  • Added Base#render(:xml => xml) that works just like Base#render(:text => text), but sets the content-type to text/xml and the charset to UTF-8 [DHH]
  • Integration test‘s url_for now runs in the context of the last request (if any) so after post /products/show/1 url_for :action => ‘new’ will yield /product/new [Tobias Luetke]
  • Re-added mixed-in helper methods for the JavascriptGenerator. Moved JavascriptGenerators methods to a module that is mixed in after the helpers are added. Also fixed that variables set in the enumeration methods like collect are set correctly. Documentation added for the enumeration methods [Rick Olson]. Examples:
      page.select('#items li').collect('items') do |element|
    element.hide
  end
  # => var items = $$('#items li').collect(function(value, index) { return value.hide(); });
  • Added plugin support for parameter parsers, which allows for better support for REST web services. By default, posts submitted with the application/xml content type is handled by creating a XmlSimple hash with the same name as the root element of the submitted xml. More handlers can easily be registered like this:
      # Assign a new param parser to a new content type
  ActionController::Base.param_parsers['application/atom+xml'] = Proc.new do |data|
    node = REXML::Document.new(post)
   { node.root.name => node.root }
  end

  # Assign the default XmlSimple to a new content type
  ActionController::Base.param_parsers['application/backpack+xml'] = :xml_simple

Default YAML web services were retired, ActionController::Base.param_parsers carries an example which shows how to get this functionality back. As part of this new plugin support, request.[formatted_post?, xml_post?, yaml_post? and post_format] were all deprecated in favor of request.content_type [Tobias Luetke]

  • Fixed Effect.Appear in effects.js to work with floats in Safari 3524, 3813, 3044 [Thomas Fuchs]
  • Fixed that default image extension was not appended when using a full URL with AssetTagHelper#image_tag 4032, 3728 [rubyonrails@beautifulpixel.com]
  • Added that page caching will only happen if the response code is less than 400 4033 [g.bucher@teti.ch]
  • Add ActionController::IntegrationTest to allow high-level testing of the way the controllers and routes all work together [Jamis Buck]
  • Added support to AssetTagHelper#javascript_include_tag for having :defaults appear anywhere in the list, so you can now make one call ala javascript_include_tag(:defaults, "my_scripts") or javascript_include_tag("my_scripts", :defaults) depending on how you want the load order 3506 [Bob Silva]
  • Added support for visual effects scoped queues to the visual_effect helper 3530 [Abdur-Rahman Advany]
  • Added .rxml (and any non-rhtml template, really) supportfor CaptureHelper#content_for and CaptureHelper#capture 3287 [Brian Takita]
  • Added script.aculo.us drag and drop helpers to RJS [Thomas Fuchs]. Examples:
      page.draggable 'product-1'
  page.drop_receiving 'wastebasket', :url => { :action => 'delete' }
  page.sortable 'todolist', :url => { action => 'change_order' }
  • Fixed that form elements would strip the trailing [] from the first parameter 3545 [ruby@bobsilva.com]
  • During controller resolution, update the NameError suppression to check for the expected constant. [Nicholas Seckar]
  • Update script.aculo.us to V1.5.3 [Thomas Fuchs]
  • Added various InPlaceEditor options, 3746, 3891, 3896, 3906 [Bill Burcham, ruairi, sl33p3r]
  • Added :count option to pagination that‘ll make it possible for the ActiveRecord::Base.count call to using something else than * for the count. Especially important for count queries using DISTINCT 3839 [skaes]
  • Update script.aculo.us to V1.5.2 [Thomas Fuchs]
  • Added element and collection proxies to RJS [DHH]. Examples:
      page['blank_slate']                  # => $('blank_slate');
  page['blank_slate'].show             # => $('blank_slate').show();
  page['blank_slate'].show('first').up # => $('blank_slate').show('first').up();

  page.select('p')                      # => $$('p');
  page.select('p.welcome b').first      # => $$('p.welcome b').first();
  page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide();
  • Add JavaScriptGenerator#replace for replacing an element‘s "outer HTML". 3246 [tom@craz8.com, Sam Stephenson]
  • Remove over-engineered form_for code for a leaner implementation. [Nicholas Seckar]
  • Document form_for‘s :html option. [Nicholas Seckar]
  • Major components cleanup and speedup. 3527 [Stefan Kaes]
  • Fix problems with pagination and :include. [Kevin Clark]
  • Add ActiveRecordTestCase for testing AR integration. [Kevin Clark]
  • Add Unit Tests for pagination [Kevin Clark]
  • Add :html option for specifying form tag options in form_for. [Sam Stephenson]
  • Replace dubious controller parent class in filter docs. 3655, 3722 [info@rhalff.com, eigentone@gmail.com]
  • Don‘t interpret the :value option on text_area as an html attribute. Set the text_area‘s value. 3752 [gabriel@gironda.org]
  • Fix remote_form_for creates a non-ajax form. [Rick Olson]
  • Don‘t let arbitrary classes match as controllers — a potentially dangerous bug. [Nicholas Seckar]
  • Fix Routing tests. Fix routing where failing to match a controller would prevent the rest of routes from being attempted. [Nicholas Seckar]
  • Add :builder => option to form_for and friends. [Nicholas Seckar, Rick Olson]
  • Fix controller resolution to avoid accidentally inheriting a controller from a parent module. [Nicholas Seckar]
  • Set sweeper‘s @controller to nil after a request so that the controller may be collected between requests. [Nicholas Seckar]
  • Subclasses of ActionController::Caching::Sweeper should be Reloadable. [Rick Olson]
  • Document the :xhr option for verifications. 3666 [leeo]
  • Added :only and :except controls to skip_before/after_filter just like for when you add filters [DHH]
  • Ensure that the instance variables are copied to the template when performing render :update. [Nicholas Seckar]
  • Add the ability to call JavaScriptGenerator methods from helpers called in update blocks. [Sam Stephenson] Example: module ApplicationHelper
      def update_time
    page.replace_html 'time', Time.now.to_s(:db)
    page.visual_effect :highlight, 'time'
  end

    end

    class UserController < ApplicationController

      def poll
    render :update { |page| page.update_time }
  end

    end

  • Add render(:update) to ActionView::Base. [Sam Stephenson]
  • Fix render(:update) to not render layouts. [Sam Stephenson]
  • Fixed that SSL would not correctly be detected when running lighttpd/fcgi behind lighttpd w/mod_proxy 3548 [stephen_purcell@yahoo.com]
  • Added the possibility to specify atomatic expiration for the memcachd session container 3571 [Stefan Kaes]
  • Change layout discovery to take into account the change in semantics with File.join and nil arguments. [Marcel Molina Jr.]
  • Raise a RedirectBackError if redirect_to :back is called when there‘s no HTTP_REFERER defined 3049 [kevin.clark@gmail.com]
  • Treat timestamps like datetimes for scaffolding purposes 3388 [Maik Schmidt]
  • Fix IE bug with link_to "something", :post => true 3443 [Justin Palmer]
  • Extract Test::Unit::TestCase test process behavior into an ActionController::TestProcess module. [Sam Stephenson]
  • Pass along blocks from render_to_string to render. [Sam Stephenson]
  • Add render :update for inline RJS. [Sam Stephenson] Example: class UserController < ApplicationController
      def refresh
    render :update do |page|
      page.replace_html  'user_list', :partial => 'user', :collection => @users
      page.visual_effect :highlight, 'user_list'
    end
  end

    end

  • allow nil objects for error_messages_for [Michael Koziarski]
  • Refactor human_size to exclude decimal place if it is zero. [Marcel Molina Jr.]
  • Update to Prototype 1.5.0_pre0 [Sam Stephenson]
  • Automatically discover layouts when a controller is namespaced. 2199, 3424 [me@jonnii.com rails@jeffcole.net Marcel Molina Jr.]
  • Add support for multiple proxy servers to CgiRequest#host [gaetanot@comcast.net]
  • Documentation typo fix. 2367 [Blair Zajac]
  • Remove Upload Progress. 2871 [Sean Treadway]
  • Fix typo in function name mapping in auto_complete_field. 2929 3446 [doppler@gmail.com phil.ross@gmail.com]
  • Allow auto-discovery of third party template library layouts. [Marcel Molina Jr.]
  • Have the form builder output radio button, not check box, when calling the radio button helper. 3331 [LouisStAmour@gmail.com]
  • Added assignment of the Autocompleter object created by JavaScriptMacroHelper#auto_complete_field to a local javascript variables [DHH]
  • Added :on option for PrototypeHelper#observe_field that allows you to specify a different callback hook to have the observer trigger on [DHH]
  • Added JavaScriptHelper#button_to_function that works just like JavaScriptHelper#link_to_function but uses a button instead of a href [DHH]
  • Added that JavaScriptHelper#link_to_function will honor existing :onclick definitions when adding the function call [DHH]
  • Added :disable_with option to FormTagHelper#submit_tag to allow for easily disabled submit buttons with different text [DHH]
  • Make auto_link handle nil by returning quickly if blank? [Scott Barron]
  • Make auto_link match urls with a port number specified. [Marcel Molina Jr.]
  • Added support for toggling visual effects to ScriptaculousHelper::visual_effect, 3323. [Thomas Fuchs]
  • Update to script.aculo.us to 1.5.0 rev. 3343 [Thomas Fuchs]
  • Added :select option for JavaScriptMacroHelper#auto_complete_field that makes it easier to only use part of the auto-complete suggestion as the value for insertion [Thomas Fuchs]
  • Added delayed execution of Javascript from within RJS 3264 [devslashnull@gmail.com]. Example:
      page.delay(20) do
    page.visual_effect :fade, 'notice'
  end
  • Add session ID to default logging, but remove the verbose description of every step [DHH]
  • Add the following RJS methods: [Sam Stephenson]
      * alert - Displays an alert() dialog
  * redirect_to - Changes window.location.href to simulate a browser redirect
  * call - Calls a JavaScript function
  * assign - Assigns to a JavaScript variable
  * << - Inserts an arbitrary JavaScript string
  • Fix incorrect documentation for form_for [Nicholas Seckar]
  • Don‘t include a layout when rendering an rjs template using render‘s :template option. [Marcel Molina Jr.]

*1.1.2* (December 13th, 2005)

  • Become part of Rails 1.0
  • Update to script.aculo.us 1.5.0 final (equals 1.5.0_rc6) [Thomas Fuchs]
  • Update to Prototype 1.4.0 final [Sam Stephenson]
  • Added form_remote_for (form_for meets form_remote_tag) [DHH]
  • Update to script.aculo.us 1.5.0_rc6
  • More robust relative url root discovery for SCGI compatibility. This solves the ‘SCGI routes problem’ — you no longer need to prefix all your routes with the name of the SCGI mountpoint. 3070 [Dave Ringoen]
  • Fix docs for text_area_tag. 3083. [Christopher Cotton]
  • Change form_for and fields_for method signatures to take object name and object as separate arguments rather than as a Hash. [DHH]
  • Introduce :selected option to the select helper. Allows you to specify a selection other than the current value of object.method. Specify :selected => nil to leave all options unselected. 2991 [Jonathan Viney <jonathan@bluewire.net.nz>]
  • Initialize @optional in routing code to avoid warnings about uninitialized access to an instance variable. [Nicholas Seckar]
  • Make ActionController‘s render honor the :locals option when rendering a :file. 1665. [Emanuel Borsboom, Marcel Molina Jr.]
  • Allow assert_tag(:conditions) to match the empty string when a tag has no children. Closes 2959. [Jamis Buck]
  • Update html-scanner to handle CDATA sections better. Closes 2970. [Jamis Buck]
  • Don‘t put flash in session if sessions are disabled. [Jeremy Kemper]
  • Strip out trailing &_= for raw post bodies. Closes 2868. [Sam Stephenson]
  • Pass multiple arguments to Element.show and Element.hide in JavaScriptGenerator instead of using iterators. [Sam Stephenson]
  • Improve expire_fragment documentation. 2966 [court3nay@gmail.com]
  • Correct docs for automatic layout assignment. 2610. [Charles M. Gerungan]
  • Always create new AR sessions rather than trying too hard to avoid database traffic. 2731 [Jeremy Kemper]
  • Update to Prototype 1.4.0_rc4. Closes 2943 (old Array.prototype.reverse behavior can be obtained by passing false as an argument). [Sam Stephenson]
  • Use Element.update(‘id’, ‘html’) instead of $(‘id’).innerHTML = ‘html’ in JavaScriptGenerator#replace_html so that script tags are evaluated. [Sam Stephenson]
  • Make rjs templates always implicitly skip out on layouts. [Marcel Molina Jr.]
  • Correct length for the truncate text helper. 2913 [Stefan Kaes]
  • Update to Prototype 1.4.0_rc3. Closes 1893, 2505, 2550, 2748, 2783. [Sam Stephenson]
  • Add support for new rjs templates which wrap an update_page block. [Marcel Molina Jr.]
  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]
  • Correct time_zone_options_for_select docs. 2892 [pudeyo@rpi.com]
  • Remove the unused, slow response_dump and session_dump variables from error pages. 1222 [lmarlow@yahoo.com]
  • Performance tweaks: use Set instead of Array to speed up prototype helper include? calls. Avoid logging code if logger is nil. Inline commonly-called template presence checks. 2880, 2881, 2882, 2883 [Stefan Kaes]
  • MemCache store may be given multiple addresses. 2869 [Ryan Carver <ryan@fivesevensix.com>]
  • Handle cookie parsing irregularity for certain Nokia phones. 2530 [zaitzow@gmail.com]
  • Added PrototypeHelper::JavaScriptGenerator and PrototypeHelper#update_page for easily modifying multiple elements in an Ajax response. [Sam Stephenson] Example:
      update_page do |page|
    page.insert_html :bottom, 'list', '<li>Last item</li>'
    page.visual_effect :highlight, 'list'
    page.hide 'status-indicator', 'cancel-link'
  end

    generates the following JavaScript:

      new Insertion.Bottom("list", "<li>Last item</li>");
  new Effect.Highlight("list");
  ["status-indicator", "cancel-link"].each(Element.hide);
  • Refactored JavaScriptHelper into PrototypeHelper and ScriptaculousHelper [Sam Stephenson]
  • Update to latest script.aculo.us version (as of [3031])
  • Updated docs for in_place_editor, fixes a couple bugs and offers extended support for external controls [Justin Palmer]
  • Update documentation for render :file. 2858 [Tom Werner]
  • Only include builtin filters whose filenames match /^[a-z][a-z_]*_helper.rb$/ to avoid including operating system metadata such as ._foo_helper.rb. 2855 [court3nay@gmail.com]
  • Added FormHelper#form_for and FormHelper#fields_for that makes it easier to work with forms for single objects also if they don‘t reside in instance variables [DHH]. Examples:

    <% form_for :person, @person, :url => { :action => "update" } do |f| %>

      First name: <%= f.text_field :first_name %>
  Last name : <%= f.text_field :last_name %>
  Biography : <%= f.text_area :biography %>
  Admin?    : <%= f.check_box :admin %>

    <% end %>

    <% form_for :person, person, :url => { :action => "update" } do |person_form| %>

      First name: <%= person_form.text_field :first_name %>
  Last name : <%= person_form.text_field :last_name %>

  <% fields_for :permission => person.permission do |permission_fields| %>
    Admin?  : <%= permission_fields.check_box :admin %>
  <% end %>

    <% end %>

  • options_for_select allows any objects which respond_to? :first and :last rather than restricting to Array and Range. 2824 [Jacob Robbins <jrobbins@cmj.com>, Jeremy Kemper]
  • The auto_link text helper accepts an optional block to format the link text for each url and email address. Example: auto_link(post.body) { |text| truncate(text, 10) } [Jeremy Kemper]
  • assert_tag uses exact matches for string conditions, instead of partial matches. Use regex to do partial matches. 2799 [Jamis Buck]
  • CGI::Session::ActiveRecordStore.data_column_name = ‘foobar’ to use a different session data column than the ‘data’ default. [nbpwie102@sneakemail.com]
  • Do not raise an exception when default helper is missing; log a debug message instead. It‘s nice to delete empty helpers. [Jeremy Kemper]
  • Controllers with acronyms in their names (e.g. PDFController) require the correct default helper (PDFHelper in file pdf_helper.rb). 2262 [jeff@opendbms.com]

*1.11.0* (November 7th, 2005)

  • Added request as instance method to views, so you can do <%= request.env["HTTP_REFERER"] %>, just like you can already access response, session, and the likes [DHH]
  • Fix conflict with assert_tag and Glue gem 2255 [david.felstead@gmail.com]
  • Add documentation to assert_tag indicating that it only works with well-formed XHTML 1937, 2570 [Jamis Buck]
  • Added action_pack.rb stub so that ActionPack::Version loads properly [Sam Stephenson]
  • Added short-hand to assert_tag so assert_tag :tag => "span" can be written as assert_tag "span" [DHH]
  • Added skip_before_filter/skip_after_filter for easier control of the filter chain in inheritance hierachies [DHH]. Example:
      class ApplicationController < ActionController::Base
    before_filter :authenticate
  end

  class WeblogController < ApplicationController
    # will run the :authenticate filter
  end

  class SignupController < ActionController::Base
    # will not run the :authenticate filter
    skip_before_filter :authenticate
  end
  • Added redirect_to :back as a short-hand for redirect_to(request.env["HTTP_REFERER"]) [DHH]
  • Change javascript_include_tag :defaults to not use script.aculo.us loader, which facilitates the use of plugins for future script.aculo.us and third party javascript extensions, and provide register_javascript_include_default for plugins to specify additional JavaScript files to load. Removed slider.js and builder.js from actionpack. [Thomas Fuchs]
  • Fix problem where redirecting components can cause an infinite loop [Rick Olson]
  • Added support for the queue option on visual_effect [Thomas Fuchs]
  • Update script.aculo.us to V1.5_rc4 [Thomas Fuchs]
  • Fix that render :text didn‘t interpolate instance variables 2629, 2626 [skaes]
  • Fix line number detection and escape RAILS_ROOT in backtrace Regexp [Nicholas Seckar]
  • Fixed document.getElementsByClassName from Prototype to be speedy again [Sam Stephenson]
  • Recognize ./#{RAILS_ROOT} as RAILS_ROOT in error traces [Nicholas Seckar]
  • Remove ARStore session fingerprinting [Nicholas Seckar]
  • Fix obscure bug in ARStore [Nicholas Seckar]
  • Added TextHelper#strip_tags for removing HTML tags from a string (using HTMLTokenizer) 2229 [marcin@junkheap.net]
  • Added a reader for flash.now, so it‘s possible to do stuff like flash.now[:alert] ||= ‘New if not set’ 2422 [Caio Chassot]

*1.10.2* (October 26th, 2005)

  • Reset template variables after using render_to_string [skaes@web.de]
  • Expose the session model backing CGI::Session
  • Abbreviate RAILS_ROOT in traces

*1.10.1* (October 19th, 2005)

  • Update error trace templates [Nicholas Seckar]
  • Stop showing generated routing code in application traces [Nicholas Seckar]

*1.10.0* (October 16th, 2005)

  • Make string-keys locals assigns optional. Add documentation describing depreciated state [skaes@web.de]
  • Improve line number detection for template errors [Nicholas Seckar]
  • Update/clean up documentation (rdoc)
  • Upgrade to Prototype 1.4.0_rc0 [Sam Stephenson]
  • Added assert_vaild. Reports the proper AR error messages as fail message when the passed record is invalid [Tobias Luetke]
  • Add temporary support for passing locals to render using string keys [Nicholas Seckar]
  • Clean up error pages by providing better backtraces [Nicholas Seckar]
  • Raise an exception if an attempt is made to insert more session data into the ActiveRecordStore data column than the column can hold. 2234. [justin@textdrive.com]
  • Removed references to assertions.rb from actionpack assert‘s backtraces. Makes error reports in functional unit tests much less noisy. [Tobias Luetke]
  • Updated and clarified documentation for JavaScriptHelper to be more concise about the various options for including the JavaScript libs. [Thomas Fuchs]
  • Hide "Retry with Breakpoint" button on error pages until feature is functional. [DHH]
  • Fix Request#host_with_port to use the standard port when Rails is behind a proxy. [Nicholas Seckar]
  • Escape query strings in the href attribute of URLs created by url_helper. 2333 [Michael Schuerig <michael@schuerig.de>]
  • Improved line number reporting for template errors [Nicholas Seckar]
  • Added :locals support for render :inline 2463 [mdabney@cavoksolutions.com]
  • Unset the X-Requested-With header when using the xhr wrapper in functional tests so that future requests aren‘t accidentally xhr‘ed 2352 [me@julik.nl, Sam Stephenson]
  • Unescape paths before writing cache to file system. 1877. [Damien Pollet]
  • Wrap javascript_tag contents in a CDATA section and add a cdata_section method to TagHelper 1691 [Michael Schuerig, Sam Stephenson]
  • Misc doc fixes (typos/grammar/etc). 2445. [coffee2code]
  • Speed improvement for session_options. 2287. [skaes@web.de]
  • Make cacheing binary files friendly with Windows. 1975. [Rich Olson]
  • Convert boolean form options form the tag_helper. 809. [Michael Schuerig <michael@schuerig.de>]
  • Fixed that an instance variable with the same name as a partial should be implicitly passed as the partial :object 2269 [court3nay]
  • Update Prototype to V1.4.0_pre11, script.aculo.us to [2502] [Thomas Fuchs]
  • Make assert_tag :children count appropriately. Closes 2181. [jamie@bravenet.com]
  • Forced newer versions of RedCloth to use hard breaks [DHH]
  • Added new scriptaculous options for auto_complete_field 2343 [m.stienstra@fngtps.com]
  • Don‘t prepend the asset host if the string is already a fully-qualified URL
  • Updated to script.aculo.us V1.5.0_rc2 and Prototype to V1.4.0_pre7 [Thomas Fuchs]
  • Undo condition change made in [2345] to prevent normal parameters arriving as StringIO.
  • Tolerate consecutive delimiters in query parameters. 2295 [darashi@gmail.com]
  • Streamline render process, code cleaning. Closes 2294. [skae]
  • Keep flash after components are rendered. 2291 [Rick Olson, Scott]
  • Shorten IE file upload path to filename only to match other browsers. 1507 [court3nay@gmail.com]
  • Fix open/save dialog in IE not opening files send with send_file/send_data, 2279 [Thomas Fuchs]
  • Fixed that auto_discovery_link_tag couldn‘t take a string as the URL [DHH]
  • Fixed problem with send_file and WEBrick using stdout 1812 [DHH]
  • Optimized tag_options to not sort keys, which is no longer necessary when assert_dom_equal and friend is available 1995 [skae]
  • Added assert_dom_equal and assert_dom_not_equal to compare tags generated by the helpers in an order-indifferent manner 1995 [skae]
  • Fixed that Request#domain caused an exception if the domain header wasn‘t set in the original http request 1795 [Michael Koziarski]
  • Make the truncate() helper multi-byte safe (assuming $KCODE has been set to something other than "NONE") 2103
  • Add routing tests from 1945 [ben@groovie.org]
  • Add a routing test case covering 2101 [Nicholas Seckar]
  • Cache relative_url_root for all webservers, not just Apache 2193 [skae]
  • Speed up cookie use by decreasing string copying 2194 [skae]
  • Fixed access to "Host" header with requests made by crappy old HTTP/1.0 clients 2124 [Marcel Molina]
  • Added easy assignment of fragment cache store through use of symbols for included stores (old way still works too)

    Before:

      ActionController::Base.fragment_cache_store =
    ActionController::Base::Caching::Fragments::FileStore.new("/path/to/cache/directory")

    After:

      ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory"
  • Added ActionController::Base.session_store=, session_store, and session_options to make it easier to tweak the session options (instead of going straight to ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
  • Added TextHelper#cycle to cycle over an array of values on each hit (useful for alternating row colors etc) 2154 [dave-ml@dribin.org]
  • Ensure that request.path never returns nil. Closes 1675 [Nicholas Seckar]
  • Add ability to specify Route Regexps for controllers. Closes 1917. [Sebastian Kanthak]
  • Provide Named Route‘s hash methods as helper methods. Closes 1744. [Nicholas Seckar, Steve Purcell]
  • Added :multipart option to ActiveRecordHelper#form to make it possible to add file input fields 2034 [jstirk@oobleyboo.com]
  • Moved auto-completion and in-place editing into the Macros module and their helper counterparts into JavaScriptMacrosHelper
  • Added in-place editing support in the spirit of auto complete with ActionController::Base.in_place_edit_for, JavascriptHelper#in_place_editor_field, and Javascript support from script.aculo.us 2038 [Jon Tirsen]
  • Added :disabled option to all data selects that‘ll make the elements inaccessible for change 2167, 253 [eigentone]
  • Fixed that TextHelper#auto_link_urls would include punctuation in the links 2166, 1671 [eigentone]
  • Fixed that number_to_currency(1000, {:precision => 0})) should return "$1,000", instead of "$1,000." 2122 [sd@notso.net]
  • Allow link_to_remote to use any DOM-element as the parent of the form elements to be submitted 2137 [erik@ruby-lang.nl]. Example:
      <tr id="row023">
    <td><input name="foo"/></td>
    <td><input name="bar"/></td>
    <td><%= link_to_remote 'Save', :update => "row023",
          :submit => "row023", :url => {:action => 'save_row'} %></td>
  </tr>
  • Fixed that render :partial would fail when :object was a Hash (due to backwards compatibility issues) 2148 [Sam Stephenson]
  • Fixed JavascriptHelper#auto_complete_for to only include unique items 2153 [Thomas Fuchs]
  • Fixed all AssetHelper methods to work with relative paths, such that javascript_include_tag(‘stdlib/standard’) will look in /javascripts/stdlib/standard instead of ’/stdlib/standard/’ 1963
  • Avoid extending view instance with helper modules each request. Closes 1979
  • Performance improvements to CGI methods. Closes 1980 [Skaes]
  • Added :post option to UrlHelper#link_to that makes it possible to do POST requests through normal ahref links using Javascript
  • Fixed overwrite_params
  • Added ActionController::Base.benchmark and ActionController::Base.silence to allow for easy benchmarking and turning off the log
  • Updated vendor copy of html-scanner to support better xml parsing
  • Added :popup option to UrlHelper#link_to 1996 [gabriel.gironda@gmail.com]. Examples:
      link_to "Help", { :action => "help" }, :popup => true
  link_to "Busy loop", { :action => "busy" }, :popup => ['new_window', 'height=300,width=600']
  • Drop trailing \000 if present on RAW_POST_DATA (works around bug in Safari Ajax implementation) 918
  • Fix observe_field to fall back to event-based observation if frequency <= 0 1916 [michael@schubert.cx]
  • Allow use of the :with option for submit_to_remote 1936 [jon@instance-design.co.uk]
  • AbstractRequest#domain returns nil when host is an ip address 2012 [kevin.clark@gmail.com]
  • ActionController documentation update 2051 [fbeausoleil@ftml.net]
  • Yield @content_for_ variables to templates 2058 [Sam Stephenson]
  • Make rendering an empty partial collection behave like :nothing => true 2080 [Sam Stephenson]
  • Add option to specify the singular name used by pagination.
  • Use string key to obtain action value. Allows indifferent hashes to be disabled.
  • Added ActionView::Base.cache_template_loading back.
  • Rewrote compiled templates to decrease code complexity. Removed template load caching in favour of compiled caching. Fixed template error messages. [Nicholas Seckar]
  • Fix Routing to handle :some_param => nil better. [Nicholas Seckar, Luminas]
  • Add support for :include with pagination (subject to existing constraints for :include with :limit and :offset) 1478 [michael@schubert.cx]
  • Prevent the benchmark module from blowing up if a non-HTTP/1.1 request is processed
  • Added :use_short_month option to select_month helper to show month names as abbreviations
  • Make link_to escape the javascript in the confirm option 1964 [nicolas.pouillard@gmail.com]
  • Make assert_redirected_to properly check URL‘s passed as strings 1910 [Scott Barron]
  • Make sure :layout => false is always used when rendering inside a layout
  • Use raise instead of assert_not_nil in Test::Unit::TestCase#process to ensure that the test variables (controller, request, response) have been set
  • Make sure assigns are built for every request when testing 1866
  • Allow remote_addr to be queried on TestRequest 1668
  • Fixed bug when a partial render was passing a local with the same name as the partial
  • Improved performance of test app req/sec with ~10% refactoring the render method 1823 [Stefan Kaes]
  • Improved performance of test app req/sec with 5-30% through a series of Action Pack optimizations 1811 [Stefan Kaes]
  • Changed caching/expiration/hit to report using the DEBUG log level and errors to use the ERROR log level instead of both using INFO
  • Added support for per-action session management 1763
  • Improved rendering speed on complicated templates by up to 100% (the more complex the templates, the higher the speedup) 1234 [Stephan Kaes]. This did necessasitate a change to the internals of ActionView#render_template that now has four parameters. Developers of custom view handlers (like Amrita) need to update for that.
  • Added options hash as third argument to FormHelper#input, so you can do input(‘person’, ‘zip’, :size=>10) 1719 [jeremye@bsa.ca.gov]
  • Added Base#expires_in(seconds)/Base#expires_now to control HTTP content cache headers 1755 [Thomas Fuchs]
  • Fixed line number reporting for Builder template errors 1753 [piotr]
  • Fixed assert_routing so that testing controllers in modules works as expected [Nicholas Seckar, Rick Olson]
  • Fixed bug with :success/:failure callbacks for the JavaScriptHelper methods 1730 [court3nay/Thomas Fuchs]
  • Added named_route method to RouteSet instances so that RouteSet instance methods do not prevent certain names from being used. [Nicholas Seckar]
  • Fixed routes so that routes which do not specify :action in the path or in the requirements have a default of :action => ‘index’, In addition, fixed url generation so that :action => ‘index’ does not need to be provided for such urls. [Nicholas Seckar, Markjuh]
  • Worked around a Safari bug where it wouldn‘t pass headers through if the response was zero length by having render :nothing return ’ ’ instead of ’’
  • Fixed Request#subdomains to handle "foo.foo.com" correctly

*1.9.1* (11 July, 2005)

  • Fixed that auto_complete_for didn‘t force the input string to lower case even as the db comparison was
  • Fixed that Action View should always use the included Builder, never attempt to require the gem, to ensure compatibility
  • Added that nil options are not included in tags, so tag("p", :ignore => nil) now returns <p /> not <p ignore="" /> but that tag("p", :ignore => "") still includes it 1465 [michael@schuerig.de]
  • Fixed that UrlHelper#link_to_unless/link_to_if used html_escape on the name if no link was to be applied. This is unnecessary and breaks its use with images 1649 [joergd@pobox.com]
  • Improved error message for DoubleRenderError
  • Fixed routing to allow for testing of *path components 1650 [Nicholas Seckar]
  • Added :handle as an option to sortable_element to restrict the drag handle to a given class 1642 [thejohnny]
  • Added a bunch of script.aculo.us features 1644, 1677, 1695 [Thomas Fuchs]
    • Effect.ScrollTo, to smoothly scroll the page to an element
    • Better Firefox flickering handling on SlideUp/SlideDown
    • Removed a possible memory leak in IE with draggables
    • Added support for cancelling dragging my hitting ESC
    • Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js (this makes it possible to call sortable_element on the same element more than once, e.g. in AJAX returns that modify the sortable element. all current sortable ‘stuff’ on the element will be discarded and the sortable will be rebuilt)
    • Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
    • Removed circular references from element to prevent memory leaks (still not completely gone in IE)
    • Changes to class extension in effects.js
    • Make Effect.Highlight restore any previously set background color when finishing (makes effect work with CSS classes that set a background color)
    • Fixed myriads of memory leaks in IE and Gecko-based browsers [David Zülke]
    • Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
    • Extended the auto_complete_field helper to accept tokens option
    • Changed object extension mechanism to favor Object.extend to make script.aculo.us easily adaptable to support 3rd party libs like IE7.js [David Zülke]
  • Fixed that named routes didn‘t use the default values for action and possible other parameters 1534 [Nicholas Seckar]
  • Fixed JavascriptHelper#visual_effect to use camelize such that :blind_up will work 1639 [pelletierm@eastmedia.net]
  • Fixed that a SessionRestoreError was thrown if a model object was placed in the session that wasn‘t available to all controllers. This means that it‘s no longer necessary to use the ‘model :post’ work-around in ApplicationController to have a Post model in your session.

*1.9.0* (6 July, 2005)

  • Added logging of the request URI in the benchmark statement (makes it easy to grep for slow actions)
  • Added javascript_include_tag :defaults shortcut that‘ll include all the default javascripts included with Action Pack (prototype, effects, controls, dragdrop)
  • Cache several controller variables that are expensive to calculate 1229 [skaes@web.de]
  • The session class backing CGI::Session::ActiveRecordStore may be replaced with any class that duck-types with a subset of Active Record. See docs for details 1238 [skaes@web.de]
  • Fixed that hashes was not working properly when passed by GET to lighttpd 849 [Nicholas Seckar]
  • Fixed assert_template nil will be true when no template was rendered 1565 [maceywj@telus.net]
  • Added :prompt option to FormOptions#select (and the users of it, like FormOptions#select_country etc) to create "Please select" style descriptors 1181 [Michael Schuerig]
  • Added JavascriptHelper#update_element_function, which returns a Javascript function (or expression) that‘ll update a DOM element according to the options passed 933 [mortonda@dgrmm.net]. Examples:
      <%= update_element_function("products", :action => :insert, :position => :bottom, :content => "<p>New product!</p>") %>

  <% update_element_function("products", :action => :replace, :binding => binding) do %>
    <p>Product 1</p>
    <p>Product 2</p>
  <% end %>
  • Added :field_name option to DateHelper#select_(year|month|day) to deviate from the year/month/day defaults 1266 [Marcel Molina]
  • Added JavascriptHelper#draggable_element and JavascriptHelper#drop_receiving_element to facilitate easy dragging and dropping through the script.aculo.us libraries 1578 [Thomas Fuchs]
  • Added that UrlHelper#mail_to will now also encode the default link title 749 [f.svehla@gmail.com]
  • Removed the default option of wrap=virtual on FormHelper#text_area to ensure XHTML compatibility 1300 [thomas@columbus.rr.com]
  • Adds the ability to include XML CDATA tags using Builder 1563 [Josh Knowles]. Example:
      xml.cdata! "some text" # => <![CDATA[some text]]>
  • Added evaluation of <SCRIPT> blocks in content returned to Ajax calls 1577 [Thomas Fuchs/court3nay/Sean Treadway]
  • Directly generate paths with a leading slash instead of tacking it on later. 1543 [Nicholas Seckar]
  • Fixed errant parameter modification in functional tests. 1542 [Nicholas Seckar]
  • Routes fail with leading slash 1540 [Nicholas Seckar]
  • Added support for graceful error handling of Ajax calls 1217 [Jamis Buck/Thomas Fuchs]. Example:
      link_to_remote(
    "test",
    :url => { :action => "faulty" },
    :update => { :success => "good", :failure => "bad" },
    403 => "alert('Forbidden- got ya!')",
    404 => "alert('Nothing there...?')",
    :failure => "alert('Unkown error ' + request.status)")
  • Attempt to explicitly flush the output at the end of CgiProcess#out
  • Fixed assert_redirected_to to handle absolute controller paths properly 1472 [Rick Olson/Nicholas Seckar]
  • Added event-based observations when frequency is not set on observe_field/form 1474 [flash@vanklinkenbergsoftware.nl]
  • Added script.aculo.us Javascripts (controls.js, dragdrop.js, effects.js) (NEEDS MORE DESCRIPTION) 1509 [Thomas Fuchs]
  • Fixed prototype to consider all fields it doesn‘t know as text (such as Safari‘s search) just like the browser in its serialization 1497 [Sean Treadway]
  • Improved performance of Routes generation by a factor of 5 1434 [Nicholas Seckar]
  • Added named routes (NEEDS BETTER DESCRIPTION) 1434 [Nicholas Seckar]
  • Improved AbstractRequest documentation 1483 [court3nay@gmail.com]
  • Added ActionController::Base.allow_concurrency to control whether the application is thread-safe, so multi-threaded servers like WEBrick knows whether to apply a mutex around the performance of each action. Turned off by default. EXPERIMENTAL FEATURE.
  • Added TextHelper#word_wrap(text, line_length = 80) 1449 [tuxie@dekadance.se]
  • Added a fall-through action for form_remote_tag that‘ll be used in case Javascript is unavailable 1459 [Scott Barron]. Example:
      form_remote_tag :html => { :action => url_for(:controller => "some", :action => "place") }
  • Added :xhr => true/false option to verify so you can ensure that a request is coming from an Ajax call or not 1464 [Thomas Fuchs]
  • Added tag_options as a third parameter to AssetHelper#auto_discovery_link_tag to control options like the title of the link 1430 [kevin.clark@gmail.com]
  • Added option to pass in parameters to CaptureHelper#capture, so you can create more advanced view helper methods 1466 [duane.johnson@gmail.com]. Example:
      <% show_calendar(:year => 2005, :month => 6) do |day, options| %>
    <% options[:bgcolor] = '#dfd' if 10..15.include? day %>
    [<%= day %>]
  <% end %>
  • Changed the default name of the input tag generated by FormTagHelper#submit_tag from "submit" to "commit" so it doesn‘t clash with form.submit() calls in Javascript 1271
  • Fixed relative urls support for lighttpd 1048 [Nicholas Seckar/maznawak@nerim.net]
  • Correct distance_of_time_in_words for integer arguments and make the second arg optional, treating the first arg as a duration in seconds. 1458 [madrobby <thomas@fesch.at>]
  • Fixed query parser to deal gracefully with equal signs inside keys and values 1345 [gorou]. Example: /?sig=abcdef=:foobar=&x=y will pass now.
  • Added Cuba to country list 1351 [todd]
  • Fixed radio_button to work with numeric values 1352 [demetrius]
  • Added :extension option to NumberHelper#number_to_phone 1361 [delynnb]
  • Added button_to as a form-based solution to deal with harmful actions that should be hidden behind POSTs. This makes it just as easy as link_to to create a safe trigger for actions like destroy, although it‘s limited by being a block element, the fixed look, and a no-no inside other forms. 1371 [tom@moertel.com]
  • Fixed image_tag so an exception is not thrown just because the image is missing and alt value can‘t be generated 1395 [Marcel]
  • Added a third parameter to TextHelper#auto_link called href_options for specifying additional tag options on the links generated 1401 [tyler.kovacs@gmail.com]. Example: auto_link(text, :all, { :target => "_blank" }) to have all the generated links open in a new window.
  • Fixed TextHelper#highlight to return the text, not nil, if the phrase is blank 1409 [patrick@lenz.sh]
  • Fixed TagHelper such that :name and ‘name’ keys in the options doesn‘t result in two attributes 1455 [take_tk]
  • Ensure that helpers are only available to the controllers where they are defined and their subclasses. 1394 [kdole@tamu.edu]
  • render("foo/bar") works with a layout again
  • Fixed double-singularization on scaffolded pagination call (Address would be turned into Addres) 1216, 1404 [nilsga]
  • Removed the require hack used by functional testing to work around an earlier bug in rake.
  • Allow distance_of_time_in_words to work with any value that responds to to_time (like dates) 969
  • Support :render option for :verify 1440 [TobiasLuetke]
  • Updated vendor copy of html-scanner lib to 0.5.2, for bug fixes and optimizations. The :content option may be used as expected—to find a tag whose textual content is a particular value—in assert_tag, now.
  • Changed test requests to come from 0.0.0.0 instead of 127.0.0.1 such that they don‘t trigger debugging screens on exceptions, but instead call rescue_action_in_public
  • Modernize scaffolding to match the generator: use the new render method and change style from the warty @params["id"] to the sleek params[:id]. 1367
  • Include :id in the action generated by the form helper method. Then, for example, the controller can do Model.find(params[:id]) for both edit and update actions. Updated scaffolding to take advantage. 1367
  • Add assertions with friendly messages to TestCase#process to ensure that @controller, @request, and @response are set. 1367
  • Arrays, hashes sent via multipart posts are converted to strings 1032 [dj@omelia.org, me@julik.nl]
  • render(:layout => true) is a synonym for render(:layout => nil)
  • Make sure the benchmarking render method always returns the output of the render.
  • render(:action), render(:template) and render() are the only three calls that default to using a layout. All other render calls assume :layout => false. This also fixes send_file, which was applying a layout if one existed for the current action.
  • verify with :redirect_to won‘t redirect if a redirect or render has already been performed 1350
  • render(:partial => true) is identical to the behavior of the deprecated render_partial()
  • Fixed render(:partial => "…") to use an empty Hash for the local assigns 1365
  • Fixed Caching::Fragments::FileStore.delete to not raise an exception if the delete fails.
  • Deprecated all render_* methods in favor of consolidating all rendering behavior in Base#render(options). This enables more natural use of combining options, such as layouts. Examples:
      +---------------------------------------------------------------+-------------------------------------------------------+
  | BEFORE                                                        | AFTER                                                 |
  +---------------------------------------------------------------+-------------------------------------------------------+
  | render_with_layout "weblog/show", "200 OK", "layouts/dialog"  | render :action => "show", :layout => "dialog"         |
  | render_without_layout "weblog/show"                           | render :action => "show", :layout => false            |
  | render_action "error", "404 Not Found"                        | render :action => "error", :status => "404 Not Found" |
  | render_template "xml.div('stuff')", "200 OK", :rxml           | render :inline => "xml.div('stuff')", :type => :rxml  |
  | render_text "hello world!"                                    | render :text => "hello world!"                        |
  | render_partial_collection "person", @people, nil, :a => 1     | render :partial => "person", :collection => @people,  |
  |                                                               |        :locals => { :a => 1 }                         |
  +---------------------------------------------------------------+-------------------------------------------------------+
  • Deprecated redirect_to_path and redirect_to_url in favor of letting redirect_to do the right thing when passed either a path or url.
  • Fixed use of an integer as return code for renders, so render_text "hello world", 404 now works 1327
  • Fixed assert_redirect_to to work with redirect_to_path 869 [Nicholas Seckar]
  • Fixed escaping of :method option in remote_form_tag 1218 [Rick Olson]
  • Added Serbia and Montenegro to the country_select 1239 [todd@robotcoop.com]
  • Fixed Request#remote_ip in testing 1251 [Jeremy Kemper]
  • Fixed that compute_public_path should recognize external URLs, so image_tag(" [image] ") is not prefixed with the relative url path 1254 [victor-ronr-trac@carotena.net]
  • Added support for descending year values in DateHelper#select_year, like select_year(Date.today, :start_year => 2005, :end_year => 1900), which would count down from 2005 to 1900 instead of the other way 1274 [nwoods@mail.com]
  • Fixed that FormHelper#checkbox should return a checked checkbox if the value is the same as checked_value 1286 [Florian Weber]
  • Fixed Form.disable in Prototype 1317 [Wintermute]
  • Added accessors to logger, params, response, session, flash, and headers from the view, so you can write <% logger.info "stuff" %> instead of <% @logger.info "others" %> — more consistent with the preferred way of accessing these attributes and collections from the controller
  • Added support for POST data in form of YAML or XML, which is controller through the Content-Type header. Example request:
      Content-Type: application/xml
  <request><item><content>HelloWorld</content></item></request>

    …is the same as:

      Content-Type: application/x-yaml
  ---
  item:
    content: HelloWorld

    …is the same as:

      item[content]=HelloWorld

    Which in the end turns into { "item" => { "content" => "HelloWorld" } }. This makes it a lot easier to publish REST web services on top of your regular actions (as they won‘t care).

    Example Curl call:

      curl -H 'Content-Type: application/xml' -d '<request><item><content>KillMeMore</content></item></request>' http://www.example.com/service

    You can query to find out whether a given request came through as one of these types with:

      - request.post_format? (:url_encoded, :xml or :yaml)
  - request.formatted_post? (for either xml or yaml)
  - request.xml_post?
  - request.yaml_post?
  • Added bundling of XmlSimple by Maik Schmidt
  • Fixed that render_partial_collection should always return a string (and not sometimes an array, despite <%= %> not caring)
  • Added TextHelper#sanitize that can will remove any Javascript handlers, blocks, and forms from an input of HTML. This allows for use of HTML on public sites, but still be free of XSS issues. 1277 [Jamis Buck]
  • Fixed the HTML scanner used by assert_tag where a infinite loop could be caused by a stray less-than sign in the input 1270 [Jamis Buck]
  • Added functionality to assert_tag, so you can now do tests on the siblings of a node, to assert that some element comes before or after the element in question, or just to assert that some element exists as a sibling 1226 [Jamis Buck]
  • Added better error handling for regexp caching expiration
  • Fixed handling of requests coming from unknown HTTP methods not to kill the server
  • Added that both AssetHelper#stylesheet_link_tag and AssetHelper#javascript_include_tag now accept an option hash as the last parameter, so you can do stuff like: stylesheet_link_tag "style", :media => "all"
  • Added FormTagHelper#image_submit_tag for making submit buttons that uses images
  • Added ActionController::Base.asset_host that will then be used by all the asset helpers. This enables you to easily offload static content like javascripts and images to a separate server tuned just for that.
  • Fixed action/fragment caching using the filestore when a directory and a file wanted to use the same name. Now there‘s a .cache prefix that sidesteps the conflict 1188 [imbcmdth@hotmail.com]
  • Fixed missing id uniqueness in FormTag#radio_button 1207 [Jarkko]
  • Fixed assert_redirected_to to work with :only_path => false 1204 [Alisdair McDiarmid]
  • Fixed render_partial_collection to output an empty string instead of nil when handed an empty array 1202 [Ryan Carver]
  • Improved the speed of regular expression expirations for caching by a factor of 10 1221 [Jamis Buck]
  • Removed dumping of template assigns on the rescue page as it would very easily include a ton of data making page loads take seconds (and the information was rarely helpful) 1222
  • Added BenchmarkHelper that can measure the execution time of a block in a template and reports the result to the log. Example:
      <% benchmark "Notes section" do %>
    <%= expensive_notes_operation %>
  <% end %>

 Will add something like "Notes section (0.345234)" to the log.
  • Added ActionController::Caching::Sweeper as an improved an easier to use sweeper. The new sweepers work on a single-step approach instead of two-steps like the old ones. Before
      def after_save(record)
    @list = record.is_a?(List) ? record : record.list
  end

  def filter(controller)
    controller.expire_page(:controller => "lists", :action => %w( show public feed ), :id => @list.id)
    controller.expire_action(:controller => "lists", :action => "all")
    @list.shares.each { |share| controller.expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
  end

    ..after:

      def after_save(record)
    list = record.is_a?(List) ? record : record.list
    expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
    expire_action(:controller => "lists", :action => "all")
    list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
  end

    The new sweepers can also observe on the actions themselves by implementing methods according to (before|after)_$controller_$action. Example of a callback that‘ll be called after PagesController#update_title has been performed:

        def after_pages_update_title
      expire_fragment(%r{pages/#{controller.assigns["page"].id}/.*})
    end

    Note that missing_method is delegated to the controller instance, which is assigned in a before filter. This means that you can call expire_fragment instead of @controller.expire_fragment.

  • Added that Fragments#expire_fragment now accepts as a regular expression as the name thereby deprecating expire_matched_fragments
  • Fixed that fragments shouldn‘t use the current host and the path as part of the key like pages does
  • Added conditions to around_filters just like before_filter and after_filter

*1.8.1* (20th April, 2005)

  • Added xml_http_request/xhr method for simulating XMLHttpRequest in functional tests 1151 [Sam Stephenson]. Example:
      xhr :post, :index
  • Fixed that Ajax.Base.options.asynchronous wasn‘t being respected in Ajax.Request (thanks Jon Casey)
  • Fixed that :get, :post, and the others should take a flash array as the third argument just like process 1144 [rails@cogentdude.com]
  • Fixed a problem with Flash.now
  • Fixed stringification on all assigned hashes. The sacrifice is that assigns[:person] won‘t work in testing. Instead assigns["person"] or assigns(:person) must be used. In other words, the keys of assigns stay strings but we‘ve added a method-based accessor to appease the need for symbols.
  • Fixed that rendering a template would require a connection to the database 1146

*1.8.0* (19th April, 2005)

  • Added assert_tag and assert_no_tag as a much improved alternative to the deprecated assert_template_xpath_match 1126 [Jamis Buck]
  • Deprecated the majority of all the testing assertions and replaced them with a much smaller core and access to all the collections the old assertions relied on. That way the regular test/unit assertions can be used against these. Added documentation about how to use it all.
  • Added a wide range of new Javascript effects:
      * Effect.Puff zooms the element out and makes it smoothly transparent at the same time, giving a "puff" illusion #996 [thomas@fesch.at]
    After the animation is completed, the display property will be set to none.
    This effect will work on relative and absolute positioned elements.

  * Effect.Appear as the opposite of Effect.Fade #990 [thomas@fesch.at]
    You should return elements with style="display:none;" or a like class for this to work best and have no chance of flicker.

  * Effect.Squish for scaling down an element and making it disappear at the end #972 [thomas@fesch.at]

  * Effect.Scale for smoothly scaling images or text up and down #972 [thomas@fesch.at]

  * Effect.Fade which smoothly turns opacity from 100 to 0 and then hides the element #960 [thomas@fesch.at]
  • Added Request#xml_http_request? (and an alias xhr?) to that‘ll return true when the request came from one of the Javascript helper methods (Ajax). This can be used to give one behavior for modern browsers supporting Ajax, another to old browsers 1127 [Sam Stephenson]
  • Changed render_partial to take local assigns as the second parameter instead of an explicit object and then the assigns. So the API changes from:
      <%= render_partial "account", person, "rules" => regulations.rules %>

    …to:

      <%= render_partial "account", :account => person, :rules => regulations.rules %>

    The old API will still work, though, and render_partial "account" will still assume :account => @account.

  • Added support for web servers that use PATH_INFO instead of REQUEST_URI like IIS 1014 [BradG/Nicholas Seckar]
  • Added graceful handling of PUT, DELETE, and OPTIONS requests for a complete coverage of REST functionality 1136 [joshknowles@gmail.com]
  • Fixed that you can now pass an alternative :href option to link_to_function/remote in order to point to somewhere other than # if the javascript fails or is turned off. You can do the same with form_remote_tag by passing in :action. 1113 [Sam Stephenson]
  • Fixed DateHelper to return values on the option tags such that they‘ll work properly in IE with form_remote_tag 1024 [Scott Raymond]
  • Fixed FormTagHelper#check_box to respect checked 1049 [DelynnB]
  • Added that render_partial called from a controller will use the action name as default 828 [Dan Peterson]
  • Added Element.toggle, Element.show, and Element.hide to the prototype javascript library. Toggle.display has been deprecated, but will still work 992 [Lucas Carlson]
  • Added that deleting a cookie should not just set it to an empty string but also instantly expire it 1118 [todd@robotcoop.com]
  • Added AssetTagHelper#image_path, AssetTagHelper#javascript_path, and AssetTagHelper#stylesheet_path 1110 [Larry Halff]
  • Fixed url_for(nil) in functional tests 1116 [Alisdair McDiarmid]
  • Fixed error handling of broken layouts 1115 [Michael Schubert]
  • Added submit_to_remote that allows you to trigger an Ajax form submition at the click of the submission button, which allows for multiple targets in a single form through the use of multiple submit buttons 930 [yrashk@gmail.com]
  • Fixed pagination to work with joins 1034 [scott@sigkill.org]
  • Fixed that *rest parameter in map.connect couldn‘t accept an empty list 1037 [Dee.Zsombor@gmail.com]
  • Added :confirm option to link_to_remote just like link_to has 1082 [yrashk@fp.org.ua]
  • Added minute_step as an option to select_minute (and the helpers that use it) to jump in larger increments than just 1 minute. At 15, it would return 0, 15, 30, 45 options 1085 [ordwaye@evergreen.edu]
  • Fixed that an exception would be thrown when an empty form was submitted 1090 [jan@ulbrich-boerwang.de]
  • Moved TextHelper#human_size to NumberHelper#number_to_human_size, but kept an deprecated alias to the old method name
  • Fixed that the content-type for some browsers could include an additional \r which made wonky things happen 1067 [Thomas Fuchs]
  • Fixed that radio buttons shouldn‘t have a default size attribute 1074 [hendrik@mans.de]
  • Added ActionView::Helpers::InstanceTag::DEFAULT_RADIO_OPTIONS that contains a hash of default options for radio buttons 1074 [hendrik@mans.de]
  • Fixed that in some circumstances controllers outside of modules may have hidden ones inside modules. For example, admin/content might have been hidden by /content. 1075 [Nicholas Seckar]
  • Added JavascriptHelper#periodically_call_remote in order to create areas of a page that update automatically at a set interval 945 [Jon Tirsen]
  • Fixed Cache#expire_matched_fragments that couldn‘t recognize the difference between string and url_for options 1030 [skaes@web.de]
  • Added simulation of @request.request_uri in functional tests 1038 [Jamis Buck]
  • Fixed autolinking to work better in more cases 1013 [Jamis Buck]
  • Added the possible of using symbols in form helpers that relate to instance variables like text_field :account, :name in addition to text_field "account", "name"’
  • Fixed javascript_include_tag to output type instead of language and conform to XHTML 1018 [Rick Olson]
  • Added NumberHelper for common string representations like phone number, currency, and percentage 1015 [DeLynn]
  • Added pagination for scaffolding (10 items per page) 964 [mortonda@dgrmm.net]
  • Added assert_no_cookie and fixed assert_cookie_equal to deal with non-existing cookies 979 [Jeremy Kemper]
  • Fixed :overwrite_param so it doesn‘t delete but reject elements from @request.parameters 982 [raphinou@yahoo.com]
  • Added :method option to verify for ensuring that either GET, POST, etc is allowed 984 [Jamis Buck]
  • Added options to set cc, bcc, subject, and body for UrlHelper#mail_to 966 [DeLynn]
  • Fixed include_blank for select_hour/minute/second 527 [edward@debian.org]
  • Improved the message display on the exception handler pages 963 [Johan Sorensen]
  • Fixed that on very rare occasions, webrick would raise a NoMethodError: private method ‘split’ called for nil 1001 [Flurin Egger]
  • Fixed problem with page caching 958 [Rick Olson]

*1.7.0* (27th March, 2005)

  • Added ActionController::Base.page_cache_extension for setting the page cache file extension (the default is .html) 903 [Andreas]
  • Fixed "bad environment variable value" exception caused by Safari, Apache, and Ajax calls 918
  • Fixed that pagination_helper would ignore :params 947 [Sebastian Kanthak]
  • Added :owerwrite_params back to url_for and friends — it was AWL since the introduction of Routes 921 [raphinou]
  • Added :position option to link_to_remote/form_remote_tag that can be either :before, :top, :bottom, or :after and specifies where the return from the method should be inserted 952 [Matthew McCray/Sam Stephenson]
  • Added Effect.Highlight to prototype.js to do Yellow Fade Technique (of 37signals’ fame) on any container 952 [Sam Stephenson/courtenay]
  • Added include_seconds option as the third parameter to distance_of_time_in_words which will render "less than a minute" in higher resolution ("less than 10 seconds" etc) 944 [thomas@fesch.at]
  • Added fourth option to process in test cases to specify the content of the flash 949 [Jamis Buck]
  • Added Verifications that allows you to specify preconditions to actions in form of statements like verify :only => :update_post, :params => "admin_privileges", :redirect_to => { :action => "settings" }, which ensure that the update_post action is only called if admin_privileges is available as a parameter — otherwise the user is redirected to settings. 897 [Jamis Buck]
  • Fixed Form.Serialize for the JavascriptHelper to also seriliaze password fields 934 [dweitzman@gmail.com]
  • Added JavascriptHelper#escape_javascript as a public method (was private) and made it escape both single and double quotes and new lines 940 [mortonda@dgrmm.net]
  • Added trailing_slash option to url_for, so you can generate urls ending in a slash. Note that is currently not recommended unless you need it for special reasons since it breaks caching 937 [stian@grytoyr.net]
  • Added expire_matched_fragments(regular_expression) to clear out a lot of fragment caches at once 927 [technoweenie@gmail.com]
  • Fixed the problems with : and ? in file names for fragment caches on Windows 927 [technoweenie@gmail.com]
  • Added TextHelper#human_size for formatting file sizes, like human_size(1234567) => 1.2 MB 943 [thomas@fesch.at]
  • Fixed link_to :confirm 936 [Nicholas Seckar]
  • Improved error reporting especially around never shallowing exceptions. Debugging helpers should be much easier now 980 [Nicholas Seckar]
  • Fixed Toggle.display in prototype.js 902 [Lucas Carlson]

*1.6.0* (22th March, 2005)

  • Added a JavascriptHelper and accompanying prototype.js library that opens the world of Ajax to Action Pack with a large array of options for dynamically interacting with an application without reloading the page 884 [Sam Stephenson/David]
  • Added pagination support through both a controller and helper add-on 817 [Sam Stephenson]
  • Fixed routing and helpers to make Rails work on non-vhost setups 826 [Nicholas Seckar/Tobias Luetke]
  • Added a much improved Flash module that allows for finer-grained control on expiration and allows you to flash the current action 839 [Caio Chassot]. Example of flash.now:
      class SomethingController < ApplicationController
    def save
      ...
      if @something.save
        # will redirect, use flash
        flash[:message] = 'Save successful'
        redirect_to :action => 'list'
      else
        # no redirect, message is for current action, use flash.now
        flash.now[:message] = 'Save failed, review'
        render_action 'edit'
      end
    end
  end
  • Added to_param call for parameters when composing an url using url_for from something else than strings 812 [Sam Stephenson]. Example:
      class Page
    def initialize(number)
      @number = number
    end
    # ...
    def to_param
      @number.to_s
    end
  end

    You can now use instances of Page with url_for:

      class BarController < ApplicationController
    def baz
      page = Page.new(4)
      url = url_for :page => page # => "http://foo/bar/baz?page=4"
    end
  end
  • Fixed form helpers to query Model#id_before_type_cast instead of Model#id as a temporary workaround for Ruby 1.8.2 warnings 818 [DeLynn B]
  • Fixed TextHelper#markdown to use blank? instead of empty? so it can deal with nil strings passed 814 [Johan Sörensen]
  • Added TextHelper#simple_format as a non-dependency text presentation helper 814 [Johan Sörensen]
  • Added that the html options disabled, readonly, and multiple can all be treated as booleans. So specifying disabled => :true will give disabled="disabled". 809 [mindel]
  • Added path collection syntax for Routes that will gobble up the rest of the url and pass it on to the controller 830 [rayners]. Example:
      map.connect 'categories/*path_info', :controller => 'categories', :action => 'show'

    A request for /categories/top-level-cat, would give @params[:path_info] with "top-level-cat". A request for /categories/top-level-cat/level-1-cat, would give @params[:path_info] with "top-level-cat/level-1-cat" and so forth.

    The @params[:path_info] return is really an array, but where to_s has been overwritten to do join("/").

  • Fixed options_for_select on selected line issue 624 [Florian Weber]
  • Added CaptureHelper with CaptureHelper#capture and CaptureHelper#content_for. See documentation in helper 837 [Tobias Luetke]
  • Fixed :anchor use in url_for 821 [Nicholas Seckar]
  • Removed the reliance on PATH_INFO as it was causing problems for caching and inhibited the new non-vhost support 822 [Nicholas Seckar]
  • Added assigns shortcut for @response.template.assigns to controller test cases [Jeremy Kemper]. Example:

    Before:

      def test_list
    assert_equal 5, @response.template.assigns['recipes'].size
    assert_equal 8, @response.template.assigns['categories'].size
  end

    After:

      def test_list
    assert_equal 5, assigns(:recipes).size
    assert_equal 8, assigns(:categories).size
  end
  • Added TagHelper#image_tag and deprecated UrlHelper#link_image_to (recommended approach is to combine image_tag and link_to instead)
  • Fixed textilize to be resilient to getting nil parsed (by using Object#blank? instead of String#empty?)
  • Fixed that the :multipart option in FormTagHelper#form_tag would be ignored [Yonatan Feldman]

*1.5.1* (7th March, 2005)

  • Fixed that the routes.rb file wouldn‘t be found on symlinked setups due to File.expand_path 793 [piotr@t-p-l.com]
  • Changed ActiveRecordStore to use Marshal instead of YAML as the latter proved troublesome in persisting circular dependencies. Updating existing applications MUST clear their existing session table from data to start using this updated store 739 [Jamis Buck]
  • Added shortcut :id assignment to render_component and friends (before you had to go through :params) 784 [Lucas Carlson]
  • Fixed that map.connect should convert arguments to strings 780 [Nicholas Seckar]
  • Added UrlHelper#link_to_if/link_to_unless to enable other conditions that just link_to_unless_current 757 [mindel]
  • Fixed that single quote was not escaped in a UrlHelper#link_to javascript confirm 549 [Scott Barron]
  • Removed the default border on link_image_to (it broke xhtml strict) — can be specified with :border => 0 517 [?/caleb]
  • Fixed that form helpers would treat string and symbol keys differently in html_options (and possibly create duplicate entries) 112 [Jeremy Kemper]
  • Fixed that broken pipe errors (clients disconnecting in mid-request) could bring down a fcgi process
  • Added the original exception message to session recall errors (so you can see which class wasnt required)
  • Fixed that RAILS_ROOT might not be defined when AP was loaded, so do a late initialization of the ROUTE_FILE 761 [Scott Barron]
  • Fix request.path_info and clear up LoadingModule behavior 754 [Nicholas Seckar]
  • Fixed caching to be aware of extensions (so you can cache files like api.wsdl or logo.png) 734 [Nicholas Seckar]
  • Fixed that Routes would raise NameErrors if a controller component contains characters that are not valid constant names 733 [Nicholas Seckar]
  • Added PATH_INFO access from the request that allows urls like the following to be interpreted by rails: www.example.com/dispatcher.cgi/controller/action — that makes it possible to use rails as a CGI under lighttpd and would also allow (for example) Rublog to be ported to rails without breaking existing links to Rublog-powered blogs. 728 [Jamis Buck]
  • Fixed that caching the root would result in .html not index.html 731, 734 [alisdair/Nicholas Seckar]

*1.5.0* (24th February, 2005)

  • Added Routing as a replacement for mod_rewrite pretty urls [Nicholas Seckar]. Read more in ActionController::Base.url_for and on manuals.rubyonrails.com/read/book/9
  • Added components that allows you to call other actions for their rendered response while execution another action. You can either delegate the entire response rendering or you can mix a partial response in with your other content. Read more on manuals.rubyonrails.com/read/book/14

* Fixed that proxy IPs do not follow all RFC1918 nets 251 [caleb@aei-tech.com]

  • Added Base#render_to_string to parse a template and get the result back as a string 479
  • Fixed that send_file/data can work even if render* has been called before in action processing to render the content of a file to be send for example 601
  • Added FormOptionsHelper#time_zone_select and FormOptionsHelper#time_zone_options_for_select to work with the new value object TimeZone in Active Support 688 [Jamis Buck]
  • Added FormHelper#file_field and FormTagHelper#file_field_tag for creating file upload fields
  • Added :order option for date_select that allows control over the order in which the date dropdowns is used and which of them should be used 619 [Tim Bates]. Examples:
      date_select("post", "written_on", :order => [:day, :month, :year])
  date_select("user", "birthday",   :order => [:month, :day])
  • Added ActionView::Base.register_template_handler for easy integration of an alternative template language to ERb and Builder. See test/controller/custom_handler_test.rb for a usage example 656 [Jamis Buck]
  • Added AssetTagHelper that provides methods for linking a HTML page together with other assets, such as javascripts, stylesheets, and feeds.
  • Added FormTagHelper that provides a number of methods for creating form tags that doesn‘t rely on conventions with an object assigned to the template like FormHelper does. With the FormTagHelper, you provide the names and values yourself.
  • Added Afghanistan, Iran, and Iraq to the countries list used by FormOptions#country_select and FormOptions#country_options_for_select
  • Renamed link_to_image to link_image_to (since thats what it actually does) — kept alias for the old method name
  • Fixed textilize for RedCloth3 to keep doing hardbreaks
  • Fixed that assert_template_xpath_matches did not indicate when a path was not found 658 [Eric Hodel]
  • Added TextHelper#auto_link to turn email addresses and urls into ahrefs
  • Fixed that on validation errors, scaffold couldn‘t find template 654 [mindel]
  • Added Base#hide_action(*names) to hide public methods from a controller that would otherwise have been callable through the URL. For the majority of cases, its preferred just to make the methods you don‘t want to expose protected or private (so they‘ll automatically be hidden) — but if you must have a public method, this is a way to make it uncallable. Base#hidden_actions retrieve the list of all hidden actions for the controller 644 [Nicholas Seckar]
  • Fixed that a bunch of methods from ActionController::Base was accessible as actions (callable through a URL) when they shouldn‘t have been 644 [Nicholas Seckar]
  • Added UrlHelper#current_page?(options) method to check if the url_for options passed corresponds to the current page
  • Fixed https handling on other ports than 443 [Alan Gano]
  • Added follow_redirect method for functional tests that‘ll get-request the redirect that was made. Example:
      def test_create_post
    post :create, "post" => { "title" => "Exciting!" }
    assert_redirected_to :action => "show"

    follow_redirect
    assert_rendered_file "post/show"
  end

    Limitation: Only works for redirects to other actions within the same controller.

  • Fixed double requiring of models with the same name as the controller
  • Fixed that query params could be forced to nil on a POST due to the raw post fix 562 [moriq@moriq.com]
  • Fixed that cookies shouldn‘t be frozen in TestRequest 571 [Eric Hodel]

*1.4.0* (January 25th, 2005)

  • Fixed problems with ActiveRecordStore under the development environment in Rails
  • Fixed the ordering of attributes in the xml-decleration of Builder 540 [woeye]
  • Added @request.raw_post as a convenience access to @request.env[‘RAW_POST_DATA’] 534 [Tobias Luetke]
  • Added support for automatic id-based indexing for lists of items 532 [dblack]. Example:
      <% @students.each do |@student| %>
    <%= text_field "student[]", "first_name", :size => "20" %>
    <%= text_field "student[]", "last_name" %>
    <%= text_field "student[]", "grade", :size => "5" %>
  <% end %>

    …would produce, for say David Black with id 123 and a grace of C+:

      <input id="student_123_first_name" name="student[123][first_name]" size="20"     size="30" type="text" value="David" />
  <input id="student_123_last_name" name="student[123][last_name]" size="30"  type="text" value="Black" />
  <input id="student_123_grade" name="student[123][grade]" size="5" type="text"  value="C+" />
  • Added :application_prefix to url_for and friends that makes it easier to setup Rails in non-vhost environments 516 [Jamis Buck]
  • Added :encode option to mail_to that‘ll allow you to masquarede the email address behind javascript or hex encoding 494 [Lucas Carlson]
  • Fixed that the content-header was being set to application/octet_stream instead of application/octet-stream on send_date/file [Alexey]
  • Removed the need for passing the binding when using CacheHelper#cache
  • Added TestResponse#binary_content that‘ll return as a string the data sent through send_data/send_file for testing 500 [Alexey]
  • Added @request.env[‘RAW_POST_DATA’] for people who need access to the data before Ruby‘s CGI has parsed it 505 [Jeremy Kemper]
  • Fixed that a default fragment store wan‘t being set to MemoryStore as intended.
  • Fixed that all redirect and render calls now return true, so you can use the pattern of "do and return". Example:
      def show
    redirect_to(:action => "login") and return unless @person.authenticated?
    render_text "I won't happen unless the person is authenticated"
  end
  • Added that renders and redirects called in before_filters will have the same effect as returning false: stopping the chain. Example:
      class WeblogController
    before_filter { |c| c.send(:redirect_to_url("http://www.farfaraway.com")}) }

    def hello
      render_text "I will never be called"
    end
  end
  • Added that only one render or redirect can happen per action. The first call wins and subsequent calls are ignored. Example:
      def do_something
    redirect_to :action => "elsewhere"
    render_action "overthere"
  end

    Only the redirect happens. The rendering call is simply ignored.

*1.3.1* (January 18th, 2005)

  • Fixed a bug where cookies wouldn‘t be set if a symbol was used instead of a string as the key
  • Added assert_cookie_equal to assert the contents of a named cookie
  • Fixed bug in page caching that prevented it from working at all

*1.3.0* (January 17th, 2005)

  • Added an extensive caching module that offers three levels of granularity (page, action, fragment) and a variety of stores. Read more in ActionController::Caching.
  • Added the option of passing a block to ActiveRecordHelper#form in order to add more to the auto-generated form 469 [dom@sisna.com]
      form("entry", :action => "sign") do |form|
    form << content_tag("b", "Department")
    form << collection_select("department", "id", @departments, "id", "name")
  end
  • Added arrays as a value option for params in url_for and friends 467 [Eric Anderson]. Example:
      url_for(:controller => 'user', :action => 'delete', :params => { 'username' =>  %( paul john steve ) } )
  # => /user/delete?username[]=paul&username[]=john&username[]=steve
  • Fixed that controller tests can now assert on the use of cookies 466 [Alexey]
  • Fixed that send_file would "remember" all the files sent by adding to the headers again and again 458 [Jeremy Kemper]
  • Fixed url rewriter confusion when the controller or action name was a substring of the controller_prefix or action_prefix
  • Added conditional layouts like layout "weblog_standard", :except => :rss 452 [Marcel Molina]
  • Fixed that MemCacheStore wasn‘t included by default and added default MemCache object pointing to localhost 447 [Lucas Carlson]
  • Added fourth argument to render_collection_of_partials that allows you to specify local_assigns — just like render_partial 432 [zenspider]
  • Fixed that host would choke when cgi.host returned nil 432 [Tobias Luetke]
  • Added that form helpers now take an index option 448 [Tim Bates]

    Example:

      text_field "person", "name", "index" => 3

    Becomes:

      <input type="text" name="person[3][name]" id="person_3_name" value="<%= @person.name %>" />
  • Fixed three issues with retrying breakpoints 417 [Florian Gross]
    1. Don‘t screw up pages that use multiple values for the same parameter (?foo=bar&foo=qux was converted to ?foo=barqux)
    2. Don‘t screw up all forms when you click the "Retry with Breakpoint" link multiple times instead of reloading (This caused the parameters to be added multiple times for GET forms leading to trouble.)
    3. Don‘t add ?BP-RETRY=1 multiple times
  • Added that all renders and redirects now return false, so they can be used as the last line in before_filters to stop execution.

    Before:

      def authenticate
    unless @session[:authenticated]
      redirect_to :controller => "account", :action => "login"
      return false
    end
  end

    After:

      def authenticate
    redirect_to(:controller => "account", :action => "login") unless @session[:authenticated]
  end
  • Added conditional filters 431 [Marcel]. Example:
      class JournalController < ActionController::Base
    # only require authentication if the current action is edit or delete
    before_filter :authorize, :only_on => [ :edit, :delete ]

    private
      def authorize
        # redirect to login unless authenticated
      end
  end
  • Added Base#render_nothing as a cleaner way of doing render_text "" when you‘re not interested in returning anything but an empty response.
  • Added the possibility of passing nil to UrlHelper#link_to to use the link itself as the name

*1.2.0* (January 4th, 2005)

  • Added MemCacheStore for storing session data in Danga‘s MemCache system [Bob Cottrell] Depends on: MemCached server (www.danga.com/memcached/), MemCache client (raa.ruby-lang.org/project/memcache/)
  • Added thread-safety to the DRbStore 66, 389 [Ben Stiglitz]
  • Added DateHelper#select_time and DateHelper#select_second 373 [Scott Baron]
  • Added :host and :protocol options to url_for and friends to redirect to another host and protocol than the current.
  • Added class declaration for the MissingFile exception 388 [Kent Sibilev]
  • Added "short hypertext note with a hyperlink to the new URI(s)" to redirects to fulfill compliance with RFC 2616 (HTTP/1.1) section 10.3.3 397 [Tim Bates]
  • Added second boolean parameter to Base.redirect_to_url and Response#redirect to control whether the redirect is permanent or not (301 vs 302) 375 [Hodel]
  • Fixed redirects when the controller and action is named the same. Still haven‘t fixed same controller, module, and action, though 201 [Josh]
  • Fixed problems with running multiple functional tests in Rails under 1.8.2 by including hack for test/unit weirdness
  • Fixed that @request.remote_ip didn‘t work in the test environment 369 [Bruno Mattarollo]

*1.1.0*

  • Added search through session to clear out association caches at the end of each request. This makes it possible to place Active Record objects in the session without worrying about stale data in the associations (the main object is still subject to caching, naturally) 347 [Tobias Luetke]
  • Added more informative exception when using helper :some_helper and the helper requires another file that fails, you‘ll get an error message tells you what file actually failed to load, rather than falling back on assuming it was the helper file itself 346 [dblack]
  • Added use of *_before_type_cast for all input and text fields. This is helpful for getting "100,000" back on a integer-based validation where the value would normally be "100".
  • Added Request#port_string to get something like ":8080" back on 8080 and "" on 80 (or 443 with https).
  • Added Request#domain (returns string) and Request#subdomains (returns array).
  • Added POST support for the breakpoint retries, so form processing that raises an exception can be retried with the original request [Florian Gross]
  • Fixed regression with Base#reset_session that wouldn‘t use the DEFAULT_SESSION_OPTIONS [adam@the-kramers.net]
  • Fixed error rendering of rxml documents to not just swallow the exception and return 0 (still not guessing the right line, but hey)
  • Fixed that textilize and markdown would instantiate their engines even on empty strings. This also fixes 333 [Ulysses]
  • Fixed UrlHelper#link_to_unless so it doesn‘t care if the id is a string or fixnum [zenspider]

*1.0.1*

  • Fixed a bug that would cause an ApplicationController to require itself three times and hence cause filters to be run three times [evl]

*1.0*

  • Added that controllers will now attempt to require a model dependency with their name and in a singular attempt for their name. So both PostController and PostsController will automatically have the post.rb model required. If no model is found, no error is raised, as it is then expected that no match is available and the programmer will have included his own models.
  • Fixed DateHelper#date_select so that you can pass include_blank as an option even if you don‘t use start_year and end_year 59 [what-a-day]
  • Added that controllers will now search for a layout in $template_root/layouts/$controller_name.r(html|xml), so PostsController will look for layouts/posts.rhtml or layouts/posts.rxml and automatically configure this layout if found 307 [Marcel]
  • Added FormHelper#radio_button to work with radio buttons like its already possible with check boxes [Michael Koziarski]
  • Added TemplateError#backtrace that makes it much easier to debug template errors from unit and functional tests
  • Added display of error messages with scaffolded form pages
  • Added option to ERB templates to swallow newlines by using <% if something -%> instead of just <% if something %>. Example:
      class SomeController < ApplicationController
  <% if options[:scaffold] %>
    scaffold :<%= singular_name %>
  <% end %>
    helper :post

    …produces this on post as singular_name:

      class SomeController < ApplicationController

    scaffold :post

    helper :post

    …where as:

      class SomeController < ApplicationController
  <% if options[:scaffold] -%>
    scaffold :<%= singular_name %>
  <% end -%>
    helper :post

    …produces:

      class SomeController < ApplicationController
    scaffold :post
    helper :post

    [This undocumented gem for ERb was uncovered by bitsweat]

  • Fixed CgiRequest so that it‘ll now accept session options with Symbols as keys (as the documentation points out) [Suggested by Andreas]
  • Added that render_partial will always by default include a counter with value 1 unless there is a counter passed in via the local_assigns hash that overrides it. As a result, render_collection_of_partials can still be written in terms of render_partial and partials that make use of a counter can be called without problems from both render_collection_of_partials as well as render_partial 295 [marcel]
  • Fixed CgiRequest#out to fall back to write if $stdout doesn‘t have syswrite [Jeremy Kemper]
  • Fixed all helpers so that they use XHTML compliant double quotes for values instead of single quotes [htonl/bitsweat]
  • Added link_to_image(src, options = {}, html_options = {}). Documentation:
      Creates a link tag to the image residing at the +src+ using an URL created by the set of +options+. See the valid options in
  link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to
  get a link tag that just points without consideration. The <tt>html_options</tt> works jointly for the image and ahref tag by
  letting the following special values enter the options on the image and the rest goes to the ahref:

  ::alt: If no alt text is given, the file name part of the +src+ is used (capitalized and without the extension)
  ::size: Supplied as "XxY", so "30x45" becomes width="30" and height="45"
  ::align: Sets the alignment, no special features

  The +src+ can be supplied as a...
  * full path, like "/my_images/image.gif"
  * file name, like "rss.gif", that gets expanded to "/images/rss.gif"
  * file name without extension, like "logo", that gets expanded to "/images/logo.png"
  • Fixed to_input_field_tag so it no longer explicitly uses InstanceTag.value if value was specified in the options hash [evl]
  • Added the possibility of having validate be protected for assert_(in)valid_column 263 [Tobias Luetke]
  • Added that ActiveRecordHelper#form now calls url_for on the :action option.
  • Added all the HTTP methods as alternatives to the generic "process" for functional testing 276 [Tobias Luetke]. Examples:
      # Calls Controller#miletone with a GET request
  process :milestone

  # Calls Controller#miletone with a POST request that has parameters
  post :milestone, { "name" => "David" }

  # Calls Controller#milestone with a HEAD request that has both parameters and session data
  head :milestone, { "id" => 1 }, { "user_id" => 23 }

    This is especially useful for testing idiomatic REST web services.

  • Added proper handling of HEAD requests, so that content isn‘t returned (Request#head? added as well) 277 [Eric Hodel]
  • Added indifference to whether @headers["Content-Type"], @headers["Content-type"], or @headers["content-type"] is used.
  • Added TestSession#session_id that returns an empty string to make it easier to functional test applications that doesn‘t use cookie-based sessions 275 [jcf]
  • Fixed that cached template loading would still check the file system to see if the file existed 258 [Andreas Schwarz]
  • Added options to tailor header tag, div id, and div class on ActiveRecordHelper#error_messages_for [Josh Peek]
  • Added graceful handling of non-alphanumeric names and misplaced brackets in input parameters [Jeremy Kemper]
  • Added a new container for cookies that makes them more intuative to use. The old methods of cookie and @cookies have been deprecated.

    Examples for writing:

      cookies["user_name"] = "david" # => Will set a simple session cookie
  cookies["login"] = { "value" => "XJ-122", "expires" => Time.now + 360} # => Will set a cookie that expires in 1 hour

    Examples for reading:

      cookies["user_name"] # => "david"
  cookies.size         # => 2

    Read more in ActionController::Cookies

    NOTE: If you were using the old accessor (cookies instead of @cookies), this could potentially break your code — if you expect a full cookie object!

  • Added the opportunity to defined method_missing on a controller which will handle all requests for actions not otherwise defined 223 [timb]
  • Fixed AbstractRequest#remote_ip for users going through proxies - Patch 228 [Eric Hodel]
  • Added Request#ssl? which is shorthand for @request.protocol == "https://"
  • Added the choice to call form_tag with no arguments (resulting in a form posting to current action) [Jeremy Kemper]
  • Upgraded to Builder 1.2.1
  • Added :module as an alias for :controller_prefix to url_for and friends, so you can do redirect_to(:module => "shop", :controller => "purchases") and go to /shop/purchases/
  • Added support for controllers in modules through @params["module"].
  • Added reloading for dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use those environments for development. This is turned on by default, but can be turned off with ActionController::Base.reload_dependencies = false in production environments.

    NOTE: This will only have an effect if you use the new model, service, and observer class methods to mark dependencies. All libraries loaded through require will be "forever" cached. You can, however, use ActionController::Base.load_or_require("library") to get this behavior outside of the new dependency style.

  • Added that controllers will automatically require their own helper if possible. So instead of doing:
      class MsgController < ApplicationController
    helper :msg
  end

    …you can just do:

      class MsgController < ApplicationController
  end
  • Added dependencies_on(layer) to query the dependencies of a controller. Examples:
      MsgController.dependencies_on(:model)    # => [ :post, :comment, :attachment ]
  MsgController.dependencies_on(:service)  # => [ :notification_service ]
  MsgController.dependencies_on(:observer) # => [ :comment_observer ]
  • Added a new dependency model with the class methods model, service, and observer. Example:
      class MsgController < ApplicationController
    model    :post, :comment, :attachment
    service  :notification_service
    observer :comment_observer
  end

    These new "keywords" remove the need for explicitly calling ‘require’ in most cases. The observer method even instantiates the observer as well as requiring it.

  • Fixed that link_to would escape & in the url again after url_for already had done so

*0.9.5* (28)

  • Added helper_method to designate that a given private or protected method you should available as a helper in the view. [Jeremy Kemper]
  • Fixed assert_rendered_file so it actually verifies if that was the rendered file [htonl]
  • Added the option for sharing partial spacer templates just like partials themselves [radsaq]
  • Fixed that Russia was named twice in country_select [alexey]
  • Fixed request_origin to use remote_ip instead of remote_addr [Jeremy Kemper]
  • Fixed link_to breakage when nil was passed for html_options [alexey]
  • Fixed redirect_to on a virtual server setup with apache with a port other than the default where it would forget the port number [seanohalpin]
  • Fixed that auto-loading webrick on Windows would cause file uploads to fail [Jeremy Kemper]
  • Fixed issues with sending files on WEBrick by setting the proper binmode [Jeremy Kemper]
  • Added send_data as an alternative to send_file when the stream is not read off the filesystem but from a database or generated live [Jeremy Kemper]
  • Added a new way to include helpers that doesn‘t require the include hack and can go without the explicit require. [Jeremy Kemper]

    Before:

      module WeblogHelper
    def self.included(controller) #:nodoc:
      controller.ancestors.include?(ActionController::Base) ? controller.add_template_helper(self) : super
    end
  end

  require 'weblog_helper'
  class WeblogController < ActionController::Base
    include WeblogHelper
  end

    After:

      module WeblogHelper
  end

  class WeblogController < ActionController::Base
    helper :weblog
  end
  • Added a default content-type of "text/xml" to .rxml renders [Ryan Platte]
  • Fixed that when /controller/index was requested by the browser, url_for would generates wrong URLs [Ryan Platte]
  • Fixed a bug that would share cookies between users when using FastCGI and mod_ruby [The Robot Co-op]
  • Added an optional third hash parameter to the process method in functional tests that takes the session data to be used [alexey]
  • Added UrlHelper#mail_to to make it easier to create mailto: style ahrefs
  • Added better error messages for layouts declared with the .rhtml extension (which they shouldn‘t) [geech]
  • Added another case to DateHelper#distance_in_minutes to return "less than a minute" instead of "0 minutes" and "1 minute" instead of "1 minutes"
  • Added a hidden field to checkboxes generated with FormHelper#check_box that will make sure that the unchecked value (usually 0) is sent even if the checkbox is not checked. This relieves the controller from doing custom checking if the checkbox wasn‘t checked. BEWARE: This might conflict with your run-on-the-mill work-around code. [Tobias Luetke]
  • Fixed error_message_on to just use the first if more than one error had been added [marcel]
  • Fixed that URL rewriting with /controller/ was working but /controller was not and that you couldn‘t use :id on index [geech]
  • Fixed a bug with link_to where the :confirm option wouldn‘t be picked up if the link was a straight url instead of an option hash
  • Changed scaffolding of forms to use <label> tags instead of <b> to please W3C [evl]
  • Added DateHelper#distance_of_time_in_words_to_now(from_time) that works like distance_of_time_in_words, but where to_time is fixed to Time.now.
  • Added assert_flash_equal(expected, key, message), assert_session_equal(expected, key, message), assert_assigned_equal(expected, key, message) to test the contents of flash, session, and template assigns.
  • Improved the failure report on assert_success when the action triggered a redirection [alexey].
  • Added "markdown" to accompany "textilize" as a TextHelper method for converting text to HTML using the Markdown syntax. BlueCloth must be installed in order for this method to become available.
  • Made sure that an active session exists before we attempt to delete it [Samuel]
  • Changed link_to with Javascript confirmation to use onclick instead of onClick for XHTML validity [Scott Barron]

*0.9.0 (43)*

  • Added support for Builder-based templates for files with the .rxml extension. These new templates are an alternative to ERb that are especially useful for generating XML content, such as this RSS example from Basecamp:
      xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
    xml.channel do
      xml.title(@feed_title)
      xml.link(@url)
      xml.description "Basecamp: Recent items"
      xml.language "en-us"
      xml.ttl "40"

      for item in @recent_items
        xml.item do
          xml.title(item_title(item))
          xml.description(item_description(item)) if item_description(item)
          xml.pubDate(item_pubDate(item))
          xml.guid(@person.firm.account.url + @recent_items.url(item))
          xml.link(@person.firm.account.url + @recent_items.url(item))

          xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
        end
      end
    end
  end

  ...which will generate something like:

  <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
      <title>Web Site Redesign</title>
      <link>http://www.basecamphq.com/clients/travelcenter/1/</link>
      <description>Basecamp: Recent items</description>
      <language>en-us</language>
      <ttl>40</ttl>
      <item>
        <title>Post: don't you know</title>
        <description>&amp;lt;p&amp;gt;deeper and down&amp;lt;/p&amp;gt;</description>
        <pubDate>Fri, 20 Aug 2004 21:13:50 CEST</pubDate>
        <guid>http://www.basecamphq.com/clients/travelcenter/1/msg/assets/96976/comments</guid>
        <link>http://www.basecamphq.com/clients/travelcenter/1/msg/assets/96976/comments</link>
        <dc:creator>David H. Heinemeier</dc:creator>
      </item>
      <item>
        <title>Milestone completed: Design Comp 2</title>
        <pubDate>Mon,  9 Aug 2004 14:42:06 CEST</pubDate>
        <guid>http://www.basecamphq.com/clients/travelcenter/1/milestones/#49</guid>
        <link>http://www.basecamphq.com/clients/travelcenter/1/milestones/#49</link>
      </item>
    </channel>
  </rss>

    The "xml" local variable is automatically available in .rxml templates. You construct the template by calling a method with the name of the tag you want. Options for the tag can be specified as a hash parameter to that method.

    Builder-based templates can be mixed and matched with the regular ERb ones. The only thing that differentiates them is the extension. No new methods have been added to the public interface to handle them.

    Action Pack ships with a version of Builder, but it will use the RubyGems version if you have one installed.

    Read more about Builder on: onestepback.org/index.cgi/Tech/Ruby/StayingSimple.rdoc

    [Builder is created by Jim Weirich]

  • Added much improved support for functional testing [what-a-day].
      # Old style
  def test_failing_authenticate
    @request.request_uri = "/login/authenticate"
    @request.action = "authenticate"
    @request.request_parameters["user_name"] = "nop"
    @request.request_parameters["password"]  = ""

    response = LoginController.process_test(@request)

    assert_equal "The username and/or password you entered is invalid.", response.session["flash"]["alert"]
    assert_equal "http://37signals.basecamp.com/login/", response.headers["location"]
  end

  # New style
  def test_failing_authenticate
    process :authenticate, "user_name" => "nop", "password" => ""
    assert_flash_has 'alert'
    assert_redirected_to :action => "index"
  end

    See a full example on codepaste.org/view/paste/334

  • Increased performance by up to 100% with a revised cookie class that fixes the performance problems with the default one that ships with 1.8.1 and below. It replaces the inheritance on SimpleDelegator with DelegateClass(Array) following the suggestion from Matz on: groups.google.com/groups?th=e3a4e68ba042f842&seekm=c3sioe%241qvm%241%40news.cybercity.dk#link14
  • Added caching for compiled ERb templates. On Basecamp, it gave between 8.5% and 71% increase in performance [Andreas Schwarz].
  • Added implicit counter variable to render_collection_of_partials [Marcel]. From the docs:
      <%= render_collection_of_partials "ad", @advertisements %>

  This will render "advertiser/_ad.rhtml" and pass the local variable +ad+ to the template for display. An iteration counter
  will automatically be made available to the template with a name of the form +partial_name_counter+. In the case of the
  example above, the template would be fed +ad_counter+.
  • Fixed problems with two sessions being maintained on reset_session that would particularly screw up ActiveRecordStore.
  • Fixed reset_session to start an entirely new session instead of merely deleting the old. So you can now safely access @session after calling reset_ression and expect it to work.
  • Added @request.get?, @request.post?, @request.put?, @request.delete? as convenience query methods for @request.method [geech]
  • Added @request.method that‘ll return a symbol representing the HTTP method, such as :get, :post, :put, :delete [geech]
  • Changed @request.remote_ip and @request.host to work properly even when a proxy is in front of the application [geech]
  • Added JavaScript confirm feature to link_to. Documentation:
      The html_options have a special feature for creating javascript confirm alerts where if you pass
  :confirm => 'Are you sure?', the link will be guarded with a JS popup asking that question.
  If the user accepts, the link is processed, otherwise not.
  • Added link_to_unless_current as a UrlHelper method [Sam Stephenson]. Documentation:
      Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current
  controller, action, and id are the same as the link's, in which case only the name is returned (or the
  given block is yielded, if one exists). This is useful for creating link bars where you don't want to link
  to the page currently being viewed.
  • Fixed that UrlRewriter (the driver for url_for, link_to, etc) would blow up when the anchor was an integer [alexey]
  • Added that layouts defined with no directory defaults to layouts. So layout "weblog/standard" will use weblog/standard (as always), but layout "standard" will use layouts/standard.
  • Fixed that partials (or any template starting with an underscore) was publically viewable [Marten]
  • Added HTML escaping to text_area helper.
  • Added :overwrite_params to url_for and friends to keep the parameters as they were passed to the current action and only overwrite a subset. The regular :params will clear the slate so you need to manually add in existing parameters if you want to reuse them. [raphinou]
  • Fixed scaffolding problem with composite named objects [Moo Jester]
  • Added the possibility for shared partials. Example:
      <%= render_partial "advertisement/ad", ad %>

    This will render the partial "advertisement/_ad.rhtml" regardless of which controller this is being called from.

    [Jacob Fugal]

  • Fixed crash when encountering forms that have empty-named fields [James Prudente]
  • Added check_box form helper method now accepts true/false as well as 1/0 [what-a-day]
  • Fixed the lacking creation of all directories with install.rb [Dave Steinberg]
  • Fixed that date_select returns valid XHTML selected options [Andreas Schwarz]
  • Fixed referencing an action with the same name as a controller in url_for [what-a-day]
  • Fixed the destructive nature of Base#attributes= on the argument [Kevin Watt]
  • Changed ActionControllerError to decent from StandardError instead of Exception. It can now be caught by a generic rescue.
  • Added SessionRestoreError that is raised when a session being restored holds objects where there is no class available.
  • Added block as option for inline filters. So what used to be written as:
      before_filter Proc { |controller| return false if controller.params["stop_action"] }

    …can now be as:

      before_filter { |controller| return false if controller.params["stop_action"] }

    [Jeremy Kemper]

  • Made the following methods public (was protected): url_for, controller_class_name, controller_name, action_name This makes it easier to write filters without cheating around the encapsulation with send.
  • ActionController::Base#reset_session now sticks even if you access @session afterwards [Kent Sibilev]
  • Improved the exception logging so the log file gets almost as much as in-browser debugging.
  • Changed base class setup from AbstractTemplate/ERbTemplate to ActionView::Base. This change should be harmless unless you were accessing Action View directly in which case you now need to reference the Base class.\
  • Added that render_collection_of_partials returns nil if the collection is empty. This makes showing a “no items” message easier. For example: <%= render_collection_of_partials("message", @messages) || "No messages found." %> [Sam Stephenson]
  • Added :month_before_year as an option to date_select to get the month select before the year. Especially useful for credit card forms.
  • Added :add_month_numbers to select_month to get options like "3 - March".
  • Removed Base.has_active_layout? as it couldn‘t answer the question without the instance. Use Base#active_layout instead.
  • Removed redundant call to update on ActionController::Base#close_session [Andreas Schwarz]
  • Fixed that DRb Store accidently started its own server (instead of just client) [Andreas]
  • Fixed strip_links so it now works across multiple lines [Chad Fowler]
  • Fixed the TemplateError exception to show the proper trace on to_s (useful for unit test debugging)
  • Implemented class inheritable attributes without eval [Caio Chassot]
  • Made TextHelper#concat accept binding as it would otherwise not work
  • The FormOptionsHelper will now call to_s on the keys and values used to generate options

*0.8.5*

  • Introduced passing of locally scoped variables between templates:
      You can pass local variables to sub templates by using a hash of with the variable
  names as keys and the objects as values:

    <%= render "shared/header", { "headline" => "Welcome", "person" => person } %>

  These can now be accessed in shared/header with:

    Headline: <%= headline %>
    First name: <%= person.first_name %>
  • Introduced the concept of partials as a certain type of sub templates:
      There's also a convenience method for rendering sub templates within the current
  controller that depends on a single object (we call this kind of sub templates for
  partials). It relies on the fact that partials should follow the naming convention
  of being prefixed with an underscore -- as to separate them from regular templates
  that could be rendered on their own. In the template for Advertiser#buy, we could have:

    <% for ad in @advertisements %>
      <%= render_partial "ad", ad %>
    <% end %>

  This would render "advertiser/_ad.rhtml" and pass the local variable +ad+
  for the template to display.

  == Rendering a collection of partials

  The example of partial use describes a familar pattern where a template needs
  to iterate over a array and render a sub template for each of the elements.
  This pattern has been implemented as a single method that accepts an array and
  renders a partial by the same name of as the elements contained within. So the
  three-lined example in "Using partials" can be rewritten with a single line:

    <%= render_collection_of_partials "ad", @advertisements %>

  So this will render "advertiser/_ad.rhtml" and pass the local variable +ad+ for
  the template to display.
  • Improved send_file by allowing a wide range of options to be applied [Jeremy Kemper]:
      Sends the file by streaming it 4096 bytes at a time. This way the
  whole file doesn't need to be read into memory at once.  This makes
  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
  download any file on your server.

  Options:
  * <tt>:filename</tt> - specifies the filename the browser will see.
    Defaults to File.basename(path).
  * <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.
    Valid values are 'inline' and 'attachment' (default).
  * <tt>:buffer_size</tt> - specifies size (in bytes) of the buffer used to stream
    the file.  Defaults to 4096.

  The default Content-Type and Content-Disposition headers are
  set to download arbitrary binary files in as many browsers as
  possible.  IE versions 4, 5, 5.5, and 6 are all known to have
  a variety of quirks (especially when downloading over SSL).

  Simple download:
    send_file '/path/to.zip'

  Show a JPEG in browser:
    send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'

  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

  Also be aware that the document may be cached by proxies and browsers.
  The Pragma and Cache-Control headers declare how the file may be cached
  by intermediaries.  They default to require clients to validate with
  the server before releasing cached responses.  See
  http://www.mnot.net/cache_docs/ for an overview of web caching and
  http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
  for the Cache-Control header spec.
  • Added pluralize method to the TextHelper that makes it easy to get strings like "1 message", "3 messages"
  • Added proper escaping for the rescues [Andreas Schwarz]
  • Added proper escaping for the option and collection tags [Andreas Schwarz]
  • Fixed NaN errors on benchmarking [Jim Weirich]
  • Fixed query string parsing for URLs that use the escaped versions of & or ; as part of a key or value
  • Fixed bug with custom Content-Type headers being in addition to rather than instead of the default header. (This bug didn‘t matter with neither CGI or mod_ruby, but FCGI exploded on it) [With help from Ara T. Howard]

*0.8.0*

  • Added select, collection_select, and country_select to make it easier for Active Records to set attributes through drop-down lists of options. Example:
      <%= select "person", "gender", %w( Male Female ) %>

    …would give the following:

      <select name="person[gender]" id="person_gender"><option>Male</option><option>Female</option></select>
  • Added an option for getting multiple values on a single form name into an array instead of having the last one overwrite. This is especially useful for groups of checkboxes, which can now be written as:
      <input type="checkbox" name="rights[]" value="CREATE" />
  <input type="checkbox" name="rights[]" value="UPDATE" />
  <input type="checkbox" name="rights[]" value="DELETE" />

    …and retrieved in the controller action with:

      @params["rights"] # => [ "CREATE", "UPDATE", "DELETE" ]

    The old behavior (where the last one wins, "DELETE" in the example) is still available. Just don‘t add "[]" to the end of the name. [Scott Baron]

  • Added send_file which uses the new render_text block acceptance to make it feasible to send large files. The files is sent with a bunch of voodoo HTTP headers required to get arbitrary files to download as expected in as many browsers as possible (eg, IE hacks). Example:

    def play_movie

      send_file "/movies/that_movie.avi"

    end

    [Jeremy Kemper]

  • render_text now accepts a block for deferred rendering. Useful for streaming large files, displaying a “please wait” message during a complex search, etc. Streaming example:
      render_text do |response|
    File.open(path, 'rb') do |file|
      while buf = file.read(1024)
        print buf
      end
    end
  end

    [Jeremy Kemper]

  • Added a new Tag Helper that can generate generic tags programmatically insted of through HTML. Example:
      tag("br", "clear" => "all") => <br clear="all" />

    …that‘s usually not terribly interesting (unless you have a lot of options already in a hash), but it gives way for more specific tags, like the new form tag:

      form_tag({ :controller => "weblog", :action => "update" }, { :multipart => "true", "style" => "width: 200px"}) =>
    <form action="/weblog/update" enctype="multipart/formdata" style="width: 200px">

    There‘s even a "pretty" version for people who don‘t like to open tags in code and close them in HTML:

      <%= start_form_tag :action => "update" %>
    # all the input fields
  <%= end_form_tag %>

    (end_form_tag just returns "</form>")

  • The selected parameter in options_for_select may now also an array of values to be selected when using a multiple select. Example:
      options_for_select([ "VISA", "Mastercard", "Discover" ], ["VISA", "Discover"]) =>
    <option selected>VISA</option>\n<option>Mastercard</option>\n<option selected>Discover</option>

    [Scott Baron]

  • Changed the URL rewriter so controller_prefix and action_prefix can be used in isolation. You can now do:
      url_for(:controller_prefix => "clients")

    …or:

      url_for(:action_prefix => "category/messages")

    Neither would have worked in isolation before (:controller_prefix required a :controller and :action_prefix required an :action)

  • Started process of a cleaner separation between Action Controller and ERb-based Action Views by introducing an abstract base class for views. And Amita adapter could be fitted in more easily now.
  • The date helper methods date_select and datetime_select now also use the field error wrapping (div with class fieldWithErrors by default).
  • The date helper methods date_select and datetime_select can now discard selects
  • Added option on AbstractTemplate to specify a different field error wrapping. Example:
      ActionView::AbstractTemplate.field_error_proc = Proc.new do |html, instance|
    "<p>#{instance.method_name + instance.error_message}</p><div style='background-color: red'>#{html}</div>"
  end

    …would give the following on a Post#title (text field) error:

      <p>Title can't be empty</p>
  <div style='background-color: red'>
    <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
  </div>
  • The UrlHelper methods url_for and link_to will now by default only return paths, not complete URIs. That should make it easier to fit a Rails application behind a proxy or load-balancer. You can overwrite this by passing :only_path => false as part of the options. [Suggested by U235]
  • Fixed bug with having your own layout for use with scaffolding [Kevin Radloff]
  • Fixed bug where redirect_to_path didn‘t append the port on non-standard ports [dhawkins]
  • Scaffolding plays nicely with single-table inheritance (LoadErrors are caught) [Jeremy Kemper]
  • Scaffolding plays nice with plural models like Category/categories [Jeremy Kemper]
  • Fixed missing suffix appending in scaffolding [Kevin Radloff]

*0.7.9*

  • The "form" method now present boolean fields from PostgreSQL as drop-down menu. [Scott]
  • Scaffolding now automatically attempts to require the class that‘s being scaffolded.
  • Scaffolding will use the current active layout, instead of its own, if one has been specified. Example:
      class WeblogController < ActionController::Base
    layout "layouts/weblog"
    scaffold :post
  end

    [Suggested by Scott]

  • Changed url_for (and all the that drives, like redirect_to, link_to, link_for) so you can pass it a symbol instead of a hash. This symbol is a method reference which is then called to calculate the url. Example:
      class WeblogController < ActionController::Base
    def update
      # do some update
      redirect_to :dashboard_url
    end

    protected
      def dashboard_url
        if @project.active?
          url_for :controller => "project", :action => "dashboard"
        else
          url_for :controller => "account", :action => "dashboard"
        end
      end
  end
  • Added default_url_options to specialize behavior for all url_for (and friends) calls:
      Overwrite to implement a number of default options that all url_for-based methods will use.
  The default options should come in form of a hash, just like the one you would use for
  url_for directly. Example:

    def default_url_options(options)
      { :controller_prefix => @project.active? ? "projects/" : "accounts/" }
    end

  As you can infer from the example, this is mostly useful for situations where you want to
  centralize dynamic dissions about the urls as they stem from the business domain. Please note
  that any individual url_for call can always override the defaults set by this method.
  • Changed url_for so that an "id" passed in the :params is not treated special. You need to use the dedicated :id to get the special auto path-params treatment. Considering the url localhost:81/friends/list
      url_for(:action => "show", :params => { "id" => 5 })
    ...used to give http://localhost:81/friends/show/5
    ......now gives http://localhost:81/friends/show?id=5

  If you want the automated id behavior, do:

  url_for(:action => "show", :id => 5 )
    ....which gives http://localhost:81/friends/show/5
  • Fixed problem with anchor being inserted before path parameters with url_for (and friends)

*0.7.8*

  • Fixed session bug where you couldn‘t store any objects that didn‘t exist in the standard library (such as Active Record objects).
  • Added reset_session method for Action Controller objects to clear out all objects in the session.
  • Fixed that exceptions raised during filters are now also caught by the default rescues
  • Added new around_filter for doing before and after filtering with a single object [Florian Weber]:
      class WeblogController < ActionController::Base
    around_filter BenchmarkingFilter.new

    # Before this action is performed, BenchmarkingFilter#before(controller) is executed
    def index
    end
    # After this action has been performed, BenchmarkingFilter#after(controller) is executed
  end

  class BenchmarkingFilter
    def initialize
      @runtime
    end

    def before
      start_timer
    end

    def after
      stop_timer
      report_result
    end
  end
  • Added the options for specifying a different name and id for the form helper methods than what is guessed [Florian Weber]:
      text_field "post", "title"
    ...just gives: <input id="post_title" name="post[title]" size="30" type="text" value="" />

  text_field "post", "title", "id" => "title_for_post", "name" => "first_post_title"
    ...can now give: <input id="title_for_post" name="first_post_title" size="30" type="text" value="" />
  • Added DebugHelper with a single "debug" method for doing pretty dumps of objects in the view (now used in the default rescues to better present the contents of session and template variables)
  • Added note to log about the templates rendered within layouts (before just the layout was shown)
  • Fixed redirects on https setups [Andreas]
  • Fixed scaffolding problem on the edit action when using :suffix => true [Scott]
  • Fixed scaffolding problem where implementing list.rhtml wouldn‘t work for the index action
  • URLs generated now uses &amp; instead of just & so pages using it can validate with W3C [Spotted by Andreas]

*0.7.7*

  • Fixed bug in CGI extension that prevented multipart forms from working

*0.7.6*

  • Included ERB::Util so all templates can easily escape HTML content with <%=h @person.content %>
  • All requests are now considered local by default, so everyone will be exposed to detailed debugging screens on errors. When the application is ready to go public, set ActionController::Base.consider_all_requests_local to false, and implement the protected method local_request? in the controller to determine when debugging screens should be shown.
  • Fixed three bugs with the url_for/redirect_to/link_to handling. Considering the url localhost:81/friends/show/1
      url_for(:action => "list")
    ...used to give http://localhost:81/friends/list/1
    ......now gives http://localhost:81/friends/list

  url_for(:controller => "friends", :action => "destroy", :id => 5)
    ...used to give http://localhost:81/friends/destroy
    ......now gives http://localhost:81/friends/destroy/5

    Considering the url localhost:81/teachers/show/t

      url_for(:action => "list", :id => 5)
    ...used to give http://localhost:81/5eachers/list/t
    ......now gives http://localhost:81/teachers/list/5

    [Reported by David Morton & Radsaq]

  • Logs exception to logfile in addition to showing them for local requests
  • Protects the eruby load behind a begin/rescue block. eRuby is not required to run ActionController.
  • Fixed install.rb to also install clean_logger and the templates
  • Added ActiveRecordStore as a session option. Read more in lib/action_controller/session/active_record_store.rb [Tim Bates]
  • Change license to MIT License (and included license file in package)
  • Application error page now returns status code 500 instead of 200
  • Fixed using Procs as layout handlers [Florian Weber]
  • Fixed bug with using redirects ports other than 80
  • Added index method that calls list on scaffolding

*0.7.5*

  • First public release


File: README

File
README
Path: | activerecord/README
Modified: | Sun Mar 02 11:08:51 -0700 2008

Active Record — Object-relation mapping put on rails

Active Record connects business objects and database tables to create a persistable domain model where logic and data are presented in one wrapping. It‘s an implementation of the object-relational mapping (ORM) pattern by the same name as described by Martin Fowler:

  "An object that wraps a row in a database table or view, encapsulates
       the database access, and adds domain logic on that data."

Active Record‘s main contribution to the pattern is to relieve the original of two stunting problems: lack of associations and inheritance. By adding a simple domain language-like set of macros to describe the former and integrating the Single Table Inheritance pattern for the latter, Active Record narrows the gap of functionality between the data mapper and active record approach.

A short rundown of the major features:

  • Automated mapping between classes and tables, attributes and columns.
     class Product < ActiveRecord::Base; end

 ...is automatically mapped to the table named "products", such as:

 CREATE TABLE products (
   id int(11) NOT NULL auto_increment,
   name varchar(255),
   PRIMARY KEY  (id)
 );

 ...which again gives Product#name and Product#name=(new_name)

    Learn more

  • Associations between objects controlled by simple meta-programming macros.
     class Firm < ActiveRecord::Base
   has_many   :clients
   has_one    :account
   belongs_to :conglomorate
 end

    Learn more

  • Aggregations of value objects controlled by simple meta-programming macros.
     class Account < ActiveRecord::Base
   composed_of :balance, :class_name => "Money",
               :mapping => %w(balance amount)
   composed_of :address,
               :mapping => [%w(address_street street), %w(address_city city)]
 end

    Learn more

  • Validation rules that can differ for new or existing objects.
      class Account < ActiveRecord::Base
    validates_presence_of     :subdomain, :name, :email_address, :password
    validates_uniqueness_of   :subdomain
    validates_acceptance_of   :terms_of_service, :on => :create
    validates_confirmation_of :password, :email_address, :on => :create
  end

    Learn more

  • Callbacks as methods or queues on the entire lifecycle (instantiation, saving, destroying, validating, etc).
     class Person < ActiveRecord::Base
   def before_destroy # is called just before Person#destroy
     CreditCard.find(credit_card_id).destroy
   end
 end

 class Account < ActiveRecord::Base
   after_find :eager_load, 'self.class.announce(#{id})'
 end

    Learn more

  • Observers for the entire lifecycle
     class CommentObserver < ActiveRecord::Observer
   def after_create(comment) # is called just after Comment#save
     Notifications.deliver_new_comment("david@loudthinking.com", comment)
   end
 end

    Learn more

  • Inheritance hierarchies
     class Company < ActiveRecord::Base; end
 class Firm < Company; end
 class Client < Company; end
 class PriorityClient < Client; end

    Learn more

  • Transaction support on both a database and object level. The latter is implemented by using Transaction::Simple
      # Just database transaction
  Account.transaction do
    david.withdrawal(100)
    mary.deposit(100)
  end

  # Database and object transaction
  Account.transaction(david, mary) do
    david.withdrawal(100)
    mary.deposit(100)
  end

    Learn more

  • Reflections on columns, associations, and aggregations
      reflection = Firm.reflect_on_association(:clients)
  reflection.klass # => Client (class)
  Firm.columns # Returns an array of column descriptors for the firms table

    Learn more

  • Direct manipulation (instead of service invocation)

    So instead of (Hibernate example):

       long pkId = 1234;
   DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
   // something interesting involving a cat...
   sess.save(cat);
   sess.flush(); // force the SQL INSERT

    Active Record lets you:

       pkId = 1234
   cat = Cat.find(pkId)
   # something even more interesting involving the same cat...
   cat.save

    Learn more

  • Database abstraction through simple adapters (~100 lines) with a shared connector
     ActiveRecord::Base.establish_connection(:adapter => "sqlite", :database => "dbfile")

 ActiveRecord::Base.establish_connection(
   :adapter  => "mysql",
   :host     => "localhost",
   :username => "me",
   :password => "secret",
   :database => "activerecord"
 )

    Learn more and read about the built-in support for MySQL, PostgreSQL, SQLite, Oracle, SQLServer, and DB2.

  • Logging support for Log4r and Logger
      ActiveRecord::Base.logger = Logger.new(STDOUT)
  ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")

Simple example (1/2): Defining tables and classes (using MySQL)

Data definitions are specified only in the database. Active Record queries the database for the column names (that then serves to determine which attributes are valid) on regular object instantiation through the new constructor and relies on the column names in the rows with the finders.

   # CREATE TABLE companies (
   #   id int(11) unsigned NOT NULL auto_increment,
   #   client_of int(11),
   #   name varchar(255),
   #   type varchar(100),
   #   PRIMARY KEY  (id)
   # )

Active Record automatically links the "Company" object to the "companies" table

   class Company < ActiveRecord::Base
     has_many :people, :class_name => "Person"
   end

   class Firm < Company
     has_many :clients

     def people_with_all_clients
      clients.inject([]) { |people, client| people + client.people }
     end
   end

The foreign_key is only necessary because we didn‘t use "firm_id" in the data definition

   class Client < Company
     belongs_to :firm, :foreign_key => "client_of"
   end

   # CREATE TABLE people (
   #   id int(11) unsigned NOT NULL auto_increment,
   #   name text,
   #   company_id text,
   #   PRIMARY KEY  (id)
   # )

Active Record will also automatically link the "Person" object to the "people" table

   class Person < ActiveRecord::Base
     belongs_to :company
   end

Simple example (2/2): Using the domain

Picking a database connection for all the Active Records

   ActiveRecord::Base.establish_connection(
     :adapter  => "mysql",
     :host     => "localhost",
     :username => "me",
     :password => "secret",
     :database => "activerecord"
   )

Create some fixtures

   firm = Firm.new("name" => "Next Angle")
   # SQL: INSERT INTO companies (name, type) VALUES("Next Angle", "Firm")
   firm.save

   client = Client.new("name" => "37signals", "client_of" => firm.id)
   # SQL: INSERT INTO companies (name, client_of, type) VALUES("37signals", 1, "Firm")
   client.save

Lots of different finders

   # SQL: SELECT * FROM companies WHERE id = 1
   next_angle = Company.find(1)

   # SQL: SELECT * FROM companies WHERE id = 1 AND type = 'Firm'
   next_angle = Firm.find(1)

   # SQL: SELECT * FROM companies WHERE id = 1 AND name = 'Next Angle'
   next_angle = Company.find(:first, :conditions => "name = 'Next Angle'")

   next_angle = Firm.find_by_sql("SELECT * FROM companies WHERE id = 1").first

The supertype, Company, will return subtype instances

   Firm === next_angle

All the dynamic methods added by the has_many macro

  next_angle.clients.empty?  # true
  next_angle.clients.size    # total number of clients
  all_clients = next_angle.clients

Constrained finds makes access security easier when ID comes from a web-app

   # SQL: SELECT * FROM companies WHERE client_of = 1 AND type = 'Client' AND id = 2
   thirty_seven_signals = next_angle.clients.find(2)

Bi-directional associations thanks to the "belongs_to" macro

   thirty_seven_signals.firm.nil? # true

Examples

Active Record ships with a couple of examples that should give you a good feel for operating usage. Be sure to edit the examples/shared_setup.rb file for your own database before running the examples. Possibly also the table definition SQL in the examples themselves.

It‘s also highly recommended to have a look at the unit tests. Read more in files/RUNNING_UNIT_TESTS.html

Philosophy

Active Record attempts to provide a coherent wrapper as a solution for the inconvenience that is object-relational mapping. The prime directive for this mapping has been to minimize the amount of code needed to build a real-world domain model. This is made possible by relying on a number of conventions that make it easy for Active Record to infer complex relations and structures from a minimal amount of explicit direction.

Convention over Configuration:

  • No XML-files!
  • Lots of reflection and run-time extension
  • Magic is not inherently a bad word

Admit the Database:

  • Lets you drop down to SQL for odd cases and performance
  • Doesn‘t attempt to duplicate or replace data definitions

Download

The latest version of Active Record can be found at

  • rubyforge.org/project/showfiles.php?group_id=182

Documentation can be found at

  • ar.rubyonrails.com

Installation

The prefered method of installing Active Record is through its GEM file. You‘ll need to have RubyGems installed for that, though. If you have, then use:

  % [sudo] gem install activerecord-1.10.0.gem

You can also install Active Record the old-fashion way with the following command:

  % [sudo] ruby install.rb

from its distribution directory.

License

Active Record is released under the MIT license.

Support

The Active Record homepage is www.rubyonrails.com. You can find the Active Record RubyForge page at rubyforge.org/projects/activerecord. And as Jim from Rake says:

   Feel free to submit commits or feature requests.  If you send a patch,
   remember to update the corresponding unit tests.  If fact, I prefer
   new feature to be submitted in the form of new unit tests.

For other information, feel free to ask on the ruby-talk mailing list (which is mirrored to comp.lang.ruby) or contact david@loudthinking.com.


Class: ActiveRecord::Base

Class
ActiveRecord::Base
In: | activerecord/lib/active_record/base.rb activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb activerecord/lib/active_record/connection_adapters/mysql_adapter.rb activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
Parent: | Object

Active Record objects don‘t specify their attributes directly, but rather infer them from the table definition with which they‘re linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.

See the mapping rules in table_name and the full example in files/README.html for more insight.

Creation

Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when you‘re receiving the data from somewhere else, like an HTTP request. It works like this:

  user = User.new(:name => "David", :occupation => "Code Artist")
  user.name # => "David"

You can also use block initialization:

  user = User.new do |u|
    u.name = "David"
    u.occupation = "Code Artist"
  end

And of course you can just create a bare object and specify the attributes after the fact:

  user = User.new
  user.name = "David"
  user.occupation = "Code Artist"

Conditions

Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. The array form is to be used when the condition input is tainted and requires sanitization. The string form can be used for statements that don‘t involve tainted data. The hash form works much like the array form, except only equality and range is possible. Examples:

  class User < ActiveRecord::Base
    def self.authenticate_unsafely(user_name, password)
      find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
    end

    def self.authenticate_safely(user_name, password)
      find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
    end

    def self.authenticate_safely_simply(user_name, password)
      find(:first, :conditions => { :user_name => user_name, :password => password })
    end
  end

The authenticate_unsafely method inserts the parameters directly into the query and is thus susceptible to SQL-injection attacks if the user_name and password parameters come directly from an HTTP request. The authenticate_safely and authenticate_safely_simply both will sanitize the user_name and password before inserting them in the query, which will ensure that an attacker can‘t escape the query and fake the login (or worse).

When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That‘s done by replacing the question marks with symbols and supplying a hash with values for the matching symbol keys:

  Company.find(:first, :conditions => [
    "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
    { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
  ])

Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND operator. For instance:

  Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
  Student.find(:all, :conditions => params[:student])

A range may be used in the hash to use the SQL BETWEEN operator:

  Student.find(:all, :conditions => { :grade => 9..12 })

Overwriting default accessors

All column values are automatically available through basic accessors on the Active Record object, but sometimes you want to specialize this behavior. This can be done by overwriting the default accessors (using the same name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. Example:

  class Song < ActiveRecord::Base
    # Uses an integer of seconds to hold the length of the song

    def length=(minutes)
      write_attribute(:length, minutes * 60)
    end

    def length
      read_attribute(:length) / 60
    end
  end

You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and read_attribute(:attribute) as a shorter form.

Attribute query methods

In addition to the basic accessors, query methods are also automatically available on the Active Record object. Query methods allow you to test whether an attribute value is present.

For example, an Active Record User with the name attribute has a name? method that you can call to determine whether the user has a name:

  user = User.new(:name => "David")
  user.name? # => true

  anonymous = User.new(:name => "")
  anonymous.name? # => false

Accessing attributes before they have been typecasted

Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.

This is especially useful in validation situations where the user might supply a string for an integer field and you want to display the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn‘t what you want.

Dynamic attribute-based finders

Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name).

It‘s also possible to use multiple attributes in the same find by separating them with "and", so you get finders like Person.find_by_user_name_and_password or even Payment.find_by_purchaser_and_state_and_country. So instead of writing Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do Person.find_by_user_name_and_password(user_name, password).

It‘s even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on").

The same dynamic finder style can be used to create the object if it doesn‘t already exist. This dynamic finder is called with find_or_create_by_ and will return the object if it already exists and otherwise creates it, then returns it. Example:

  # No 'Summer' tag exists
  Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")

  # Now the 'Summer' tag does exist
  Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")

Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Example:

  # No 'Winter' tag exists
  winter = Tag.find_or_initialize_by_name("Winter")
  winter.new_record? # true

To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of a list of parameters. For example:

  Tag.find_or_create_by_name(:name => "rails", :creator => current_user)

That will either find an existing tag named "rails", or create a new one while setting the user that created it.

Saving arrays, hashes, and other non-mappable objects in text columns

Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method serialize. This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:

  class User < ActiveRecord::Base
    serialize :preferences
  end

  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 descendent of a class not in the hierarchy. Example:

  class User < ActiveRecord::Base
    serialize :preferences, Hash
  end

  user = User.create(:preferences => %w( one two three ))
  User.find(user.id).preferences    # raises SerializationTypeMismatch

Single table inheritance

Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed by overwriting Base.inheritance_column). This means that an inheritance looking like this:

  class Company < ActiveRecord::Base; end
  class Firm < Company; end
  class Client < Company; end
  class PriorityClient < Client; end

When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then fetch this row again using Company.find(:first, "name = ‘37signals’") and it will return a Firm object.

If you don‘t have a type column defined in your table, single-table inheritance won‘t be triggered. In that case, it‘ll work just like normal subclasses with no special magic for differentiating between them or reloading the right type with find.

Note, all the attributes for all the cases are kept in the same table. Read more: www.martinfowler.com/eaaCatalog/singleTableInheritance.html

Connection to multiple databases in different models

Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection and Course *and all its subclasses* will use this connection instead.

This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.

Exceptions

  • ActiveRecordError — generic error class and superclass of all other errors raised by Active Record
  • AdapterNotSpecified — the configuration hash used in establish_connection didn‘t include an :adapter key.
  • AdapterNotFound — the :adapter key used in establish_connection specified a non-existent adapter (or a bad spelling of an existing one).
  • AssociationTypeMismatch — the object assigned to the association wasn‘t of the type specified in the association definition.
  • SerializationTypeMismatch — the serialized object wasn‘t of the class specified as the second parameter.
  • ConnectionNotEstablished — no connection has been established. Use establish_connection before querying.
  • RecordNotFound — no record responded to the find* method. Either the row with the given ID doesn‘t exist or the row didn‘t meet the additional restrictions.
  • StatementInvalid — the database server rejected the SQL statement. The precise error is added in the message. Either the record with the given ID doesn‘t exist or the record didn‘t meet the additional restrictions.
  • MultiparameterAssignmentErrors — collection of errors that occurred during a mass assignment using the +attributes=+ method. The errors property of this exception contains an array of AttributeAssignmentError objects that should be inspected to determine which attributes triggered the errors.
  • AttributeAssignmentError — an error occurred while doing a mass assignment through the +attributes=+ method. You can inspect the attribute property of the exception object to determine which attribute triggered the error.

Note: The attributes listed are class-level attributes (accessible from both the class and instance level). So it‘s possible to assign a logger to the class through Base.logger= which will then be used by all instances in the current object space.

Methods
  • ==
  • ===
  • []
  • []=
  • abstract_class?
  • attr_accessible
  • attr_protected
  • attr_readonly
  • attribute_for_inspect
  • attribute_names
  • attribute_present?
  • attributes
  • attributes=
  • attributes_before_type_cast
  • base_class
  • becomes
  • benchmark
  • class_of_active_record_descendant
  • clear_active_connections!
  • clear_reloadable_connections!
  • clone
  • column_for_attribute
  • column_names
  • columns
  • columns_hash
  • compute_type
  • connected?
  • connection
  • connection
  • content_columns
  • count_by_sql
  • create
  • decrement
  • decrement!
  • decrement_counter
  • delete
  • delete_all
  • descends_from_active_record?
  • destroy
  • destroy
  • destroy_all
  • eql?
  • establish_connection
  • exists?
  • find
  • find_by_sql
  • freeze
  • frozen?
  • has_attribute?
  • hash
  • id
  • id=
  • increment
  • increment!
  • increment_counter
  • inheritance_column
  • inspect
  • inspect
  • new
  • new_record?
  • primary_key
  • readonly!
  • readonly?
  • readonly_attributes
  • reload
  • remove_connection
  • require_mysql
  • reset_column_information
  • sanitize_sql_array
  • sanitize_sql_for_assignment
  • sanitize_sql_for_conditions
  • sanitize_sql_hash_for_assignment
  • sanitize_sql_hash_for_conditions
  • save
  • save!
  • serialize
  • serialized_attributes
  • set_inheritance_column
  • set_primary_key
  • set_sequence_name
  • set_table_name
  • silence
  • table_exists?
  • table_name
  • to_param
  • toggle
  • toggle!
  • update
  • update_all
  • update_attribute
  • update_attributes
  • update_attributes!
  • update_counters
  • with_exclusive_scope
  • with_scope
Constants
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from, :lock ]
Attributes
[RW] abstract_class Set this to true if this is an abstract class (see abstract_class?).
Public Class methods
===(object)

Overwrite the default class equality method to provide support for association proxies.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1204
1204:       def ===(object)
1205:         object.is_a?(self)
1206:       end
abstract_class?()

Returns whether this class is a base AR class. If A is a base class and B descends from A, then B.base_class will return B.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1220
1220:       def abstract_class?
1221:         abstract_class == true
1222:       end
attr_accessible(*attributes)

Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, such as new(attributes) and attributes=(attributes) however, it does it in the opposite way. This locks all attributes and only allows access to the attributes specified. Assignment to attributes not in this list will be ignored and need to be set using the direct writer methods instead. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. If you‘d rather start from an all-open default and restrict attributes as needed, have a look at attr_protected.

Options

*attributes A comma separated list of symbols that represent columns not to be protected

Examples

  class Customer < ActiveRecord::Base
    attr_accessible :name, :nickname
  end

  customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
  customer.credit_rating # => nil
  customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
  customer.credit_rating # => nil

  customer.credit_rating = "Average"
  customer.credit_rating # => "Average"

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 853
853:       def attr_accessible(*attributes)
854:         write_inheritable_attribute("attr_accessible", Set.new(attributes.map(&:to_s)) + (accessible_attributes || []))
855:       end
attr_protected(*attributes)

Attributes named in this macro are protected from mass-assignment, such as new(attributes) and attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:

  class Customer < ActiveRecord::Base
    attr_protected :credit_rating
  end

  customer = Customer.new("name" => David, "credit_rating" => "Excellent")
  customer.credit_rating # => nil
  customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
  customer.credit_rating # => nil

  customer.credit_rating = "Average"
  customer.credit_rating # => "Average"

To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 819
819:       def attr_protected(*attributes)
820:         write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || []))
821:       end
attr_readonly(*attributes)

Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 863
863:        def attr_readonly(*attributes)
864:          write_inheritable_attribute("attr_readonly", Set.new(attributes.map(&:to_s)) + (readonly_attributes || []))
865:        end
base_class()

Returns the base AR subclass that this class descends from. If A extends AR::Base, A.base_class will return A. If B descends from A through some arbitrarily deep hierarchy, B.base_class will return A.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1211
1211:       def base_class
1212:         class_of_active_record_descendant(self)
1213:       end
benchmark(title, log_level = Logger::DEBUG, use_silence = true) {|| ...}

Log and benchmark multiple statements in a single block. Example:

  Project.benchmark("Creating project") do
    project = Project.create("name" => "stuff")
    project.create_manager("name" => "David")
    project.milestones << Milestone.find(:all)
  end

The benchmark is only recorded if the current level of the logger matches the log_level, which makes it easy to include benchmarking statements in production software that will remain inexpensive because the benchmark will only be conducted if the log level is low enough.

The logging of the multiple statements is turned off unless use_silence is set to false.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1184
1184:       def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
1185:         if logger && logger.level == log_level
1186:           result = nil
1187:           seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
1188:           logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
1189:           result
1190:         else
1191:           yield
1192:         end
1193:       end
clear_active_connections!()

Clears the cache which maps classes to connections.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 84
84:       def clear_active_connections!
85:         clear_cache!(@@active_connections) do |name, conn|
86:           conn.disconnect!
87:         end
88:       end
clear_reloadable_connections!()

Clears the cache which maps classes

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 91
 91:       def clear_reloadable_connections!
 92:         if @@allow_concurrency
 93:           # With concurrent connections @@active_connections is
 94:           # a hash keyed by thread id.
 95:           @@active_connections.each do |thread_id, conns|
 96:             conns.each do |name, conn|
 97:               if conn.requires_reloading?
 98:                 conn.disconnect!
 99:                 @@active_connections[thread_id].delete(name)
100:               end
101:             end
102:           end
103:         else
104:           @@active_connections.each do |name, conn|
105:             if conn.requires_reloading?
106:               conn.disconnect!
107:               @@active_connections.delete(name)
108:             end
109:           end
110:         end
111:       end
column_names()

Returns an array of column names as strings.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1092
1092:       def column_names
1093:         @column_names ||= columns.map { |column| column.name }
1094:       end
columns()

Returns an array of column objects for the table associated with this class.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1078
1078:       def columns
1079:         unless @columns
1080:           @columns = connection.columns(table_name, "#{name} Columns")
1081:           @columns.each {|column| column.primary = column.name == primary_key}
1082:         end
1083:         @columns
1084:       end
columns_hash()

Returns a hash of column objects for the table associated with this class.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1087
1087:       def columns_hash
1088:         @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
1089:       end
connected?()

Returns true if a connection that‘s accessible to this class has already been opened.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 268
268:     def self.connected?
269:       active_connections[active_connection_name] ? true : false
270:     end
connection()

Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work unrelated to any of the specific Active Records.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 73
73:       def connection
74:         if @active_connection_name && (conn = active_connections[@active_connection_name])
75:           conn
76:         else
77:           # retrieve_connection sets the cache key.
78:           conn = retrieve_connection
79:           active_connections[@active_connection_name] = conn
80:         end
81:       end
content_columns()

Returns an array of column objects where the primary id, all columns ending in "_id" or "_count", and columns used for single table inheritance have been removed.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1098
1098:       def content_columns
1099:         @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
1100:       end
count_by_sql(sql)

Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part. The use of this method should be restricted to complicated SQL queries that can‘t be executed using the ActiveRecord::Calculations class methods. Look into those before using this.

Options

sql: An SQL statement which should return a count query from the database, see the example below

Examples

  Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 729
729:       def count_by_sql(sql)
730:         sql = sanitize_conditions(sql)
731:         connection.select_value(sql, "#{name} Count").to_i
732:       end
create(attributes = nil)

Creates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.

The attributes parameter can be either be a Hash or an Array of Hashes. These Hashes describe the attributes on the objects that are to be created.

Examples

  # Create a single new object
  User.create(:first_name => 'Jamie')
  # Create an Array of new objects
  User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}])

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 567
567:       def create(attributes = nil)
568:         if attributes.is_a?(Array)
569:           attributes.collect { |attr| create(attr) }
570:         else
571:           object = new(attributes)
572:           object.save
573:           object
574:         end
575:       end
decrement_counter(counter_name, id)

Decrement a number field by one, usually representing a count.

This works the same as increment_counter but reduces the column value by 1 instead of increasing it.

Options

counter_name The name of the field that should be decremented id The id of the object that should be decremented

Examples

  # Decrement the post_count column for the record with an id of 5
  DiscussionBoard.decrement_counter(:post_count, 5)

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 797
797:       def decrement_counter(counter_name, id)
798:         update_counters(id, counter_name => -1)
799:       end
delete(id)

Delete an object (or multiple objects) where the id given matches the primary_key. A SQL DELETE command is executed on the database which means that no callbacks are fired off running this. This is an efficient method of deleting records that don‘t need cleaning up after or other actions to be taken.

Objects are not instantiated with this method.

Options

id Can be either an Integer or an Array of Integers

Examples

  # Delete a single object
  Todo.delete(1)

  # Delete multiple objects
  todos = [1,2,3]
  Todo.delete(todos)

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 622
622:       def delete(id)
623:         delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
624:       end
delete_all(conditions = nil)

Deletes the records matching conditions without instantiating the records first, and hence not calling the destroy method and invoking callbacks. This is a single SQL query, much more efficient than destroy_all.

Options

conditions Conditions are specified the same way as with find method.

Example

  Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"

This deletes the affected posts all at once with a single DELETE query. If you need to destroy dependent associations or call your before_ or after_destroy callbacks, use the destroy_all method instead.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 712
712:       def delete_all(conditions = nil)
713:         sql = "DELETE FROM #{quoted_table_name} "
714:         add_conditions!(sql, conditions, scope(:find))
715:         connection.delete(sql, "#{name} Delete all")
716:       end
descends_from_active_record?()

True if this isn‘t a concrete subclass needing a STI type condition.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1134
1134:       def descends_from_active_record?
1135:         if superclass.abstract_class?
1136:           superclass.descends_from_active_record?
1137:         else
1138:           superclass == Base || !columns_hash.include?(inheritance_column)
1139:         end
1140:       end
destroy(id)

Destroy an object (or multiple objects) that has the given id, the object is instantiated first, therefore all callbacks and filters are fired off before the object is deleted. This method is less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.

This essentially finds the object (or multiple objects) with the given id, creates a new object from the attributes, and then calls destroy on it.

Options

id Can be either an Integer or an Array of Integers

Examples

  # Destroy a single object
  Todo.destroy(1)

  # Destroy multiple objects
  todos = [1,2,3]
  Todo.destroy(todos)

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 645
645:       def destroy(id)
646:         id.is_a?(Array) ? id.each { |id| destroy(id) } : find(id).destroy
647:       end
destroy_all(conditions = nil)

Destroys the records matching conditions by instantiating each record and calling the destroy method. This means at least 2*N database queries to destroy N records, so avoid destroy_all if you are deleting many records. If you want to simply delete records without worrying about dependent associations or callbacks, use the much faster delete_all method instead.

Options

conditions Conditions are specified the same way as with find method.

Example

  Person.destroy_all "last_login < '2004-04-04'"

This loads and destroys each person one by one, including its dependent associations and before_ and after_destroy callbacks.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 694
694:       def destroy_all(conditions = nil)
695:         find(:all, :conditions => conditions).each { |object| object.destroy }
696:       end
establish_connection(spec = nil)

Establishes the connection to the database. Accepts a hash as input where the :adapter key must be specified with the name of a database adapter (in lower-case) example for regular databases (MySQL, Postgresql, etc):

  ActiveRecord::Base.establish_connection(
    :adapter  => "mysql",
    :host     => "localhost",
    :username => "myuser",
    :password => "mypass",
    :database => "somedatabase"
  )

Example for SQLite database:

  ActiveRecord::Base.establish_connection(
    :adapter => "sqlite",
    :database  => "path/to/dbfile"
  )

Also accepts keys as strings (for parsing from yaml for example):

  ActiveRecord::Base.establish_connection(
    "adapter" => "sqlite",
    "database"  => "path/to/dbfile"
  )

The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError may be returned on an error.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 204
204:     def self.establish_connection(spec = nil)
205:       case spec
206:         when nil
207:           raise AdapterNotSpecified unless defined? RAILS_ENV
208:           establish_connection(RAILS_ENV)
209:         when ConnectionSpecification
210:           clear_active_connection_name
211:           @active_connection_name = name
212:           @@defined_connections[name] = spec
213:         when Symbol, String
214:           if configuration = configurations[spec.to_s]
215:             establish_connection(configuration)
216:           else
217:             raise AdapterNotSpecified, "#{spec} database is not configured"
218:           end
219:         else
220:           spec = spec.symbolize_keys
221:           unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
222:
223:           begin
224:             require 'rubygems'
225:             gem "activerecord-#{spec[:adapter]}-adapter"
226:             require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
227:           rescue LoadError
228:             begin
229:               require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
230:             rescue LoadError
231:               raise "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{$!})"
232:             end
233:           end
234:
235:           adapter_method = "#{spec[:adapter]}_connection"
236:           if !respond_to?(adapter_method)
237:             raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
238:           end
239:
240:           remove_connection
241:           establish_connection(ConnectionSpecification.new(spec, adapter_method))
242:       end
243:     end
exists?(id_or_conditions)

Checks whether a record exists in the database that matches conditions given. These conditions can either be a single integer representing a primary key id to be found, or a condition to be matched like using ActiveRecord#find.

The id_or_conditions parameter can be an Integer or a String if you want to search the primary key column of the table for a matching id, or if you‘re looking to match against a condition you can use an Array or a Hash.

Possible gotcha: You can‘t pass in a condition as a string e.g. "name = ‘Jamie’", this would be sanitized and then queried against the primary key column as "id = ‘name = \’Jamie"

Examples

  Person.exists?(5)
  Person.exists?('5')
  Person.exists?(:name => "David")
  Person.exists?(['name LIKE ?', "%#{query}%"])

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 551
551:       def exists?(id_or_conditions)
552:         !find(:first, :select => "#{quoted_table_name}.#{primary_key}",
553:               :conditions => expand_id_conditions(id_or_conditions)).nil?
554:       end
find(*args)

Find operates with three different retrieval approaches:

  • Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised.
  • Find first: This will return the first record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned.
  • Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.

All approaches accept an options hash as their last parameter. The options are:

  • :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
  • :order: An SQL fragment like "created_at DESC, name".
  • :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
  • :limit: An integer determining the limit on the number of rows that should be returned.
  • :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
  • :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table‘s columns. Pass :readonly => false to override.
  • :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer to already defined associations. See eager loading under Associations.
  • :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not include the joined columns.
  • :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name of a database view).
  • :readonly: Mark the returned records read-only so they cannot be saved or updated.
  • :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". :lock => true gives connection‘s default exclusive lock, usually "FOR UPDATE".

Examples for find by id:

  Person.find(1)       # returns the object for ID = 1
  Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
  Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
  Person.find([1])     # returns an array for the object with ID = 1
  Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")

Note that returned records may not be in the same order as the ids you provide since database rows are unordered. Give an explicit :order to ensure the results are sorted.

Examples for find first:

  Person.find(:first) # returns the first object fetched by SELECT * FROM people
  Person.find(:first, :conditions => [ "user_name = ?", user_name])
  Person.find(:first, :order => "created_on DESC", :offset => 5)

Examples for find all:

  Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
  Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
  Person.find(:all, :offset => 10, :limit => 10)
  Person.find(:all, :include => [ :account, :friends ])
  Person.find(:all, :group => "category")

Example for find with a lock. Imagine two concurrent transactions: each will read person.visits == 2, add 1 to it, and save, resulting in two saves of person.visits = 3. By locking the row, the second transaction has to wait until the first is finished; we get the expected person.visits == 4.

  Person.transaction do
    person = Person.find(1, :lock => true)
    person.visits += 1
    person.save!
  end

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 496
496:       def find(*args)
497:         options = args.extract_options!
498:         validate_find_options(options)
499:         set_readonly_option!(options)
500:
501:         case args.first
502:           when :first then find_initial(options)
503:           when :all   then find_every(options)
504:           else             find_from_ids(args, options)
505:         end
506:       end
find_by_sql(sql)

Executes a custom sql query against your database and returns all the results. The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product object with the attributes you specified in the SQL query.

If you call a complicated SQL query which spans multiple tables the columns specified by the SELECT will be attributes of the model, whether or not they are columns of the corresponding table.

The sql parameter is a full sql query as a string. It will be called as is, there will be no database agnostic conversions performed. This should be a last resort because using, for example, MySQL specific terms will lock you to using that particular database engine or require you to change your call if you switch engines

Examples

  # A simple sql query spanning multiple tables
  Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
  > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]

  # You can use the same string replacement techniques as you can with ActiveRecord#find
  Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
  > [#<Post:0x36bff9c @attributes={"first_name"=>"The Cheap Man Buys Twice"}>, ...]

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 531
531:       def find_by_sql(sql)
532:         connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
533:       end
increment_counter(counter_name, id)

Increment a number field by one, usually representing a count.

This is used for caching aggregate values, so that they don‘t need to be computed every time. For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is shown it would have to run an SQL query to find how many posts and comments there are.

Options

counter_name The name of the field that should be incremented id The id of the object that should be incremented

Examples

  # Increment the post_count column for the record with an id of 5
  DiscussionBoard.increment_counter(:post_count, 5)

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 780
780:       def increment_counter(counter_name, id)
781:         update_counters(id, counter_name => 1)
782:       end
inheritance_column()

Defines the column name for use with single table inheritance — can be set in subclasses like so: self.inheritance_column = "type_id"

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 973
973:       def inheritance_column
974:         @inheritance_column ||= "type".freeze
975:       end
inspect()

Returns a string like ‘Post id:integer, title:string, body:text‘

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1148
1148:       def inspect
1149:         if self == Base
1150:           super
1151:         elsif abstract_class?
1152:           "#{super}(abstract)"
1153:         elsif table_exists?
1154:           attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
1155:           "#{super}(#{attr_list})"
1156:         else
1157:           "#{super}(Table doesn't exist)"
1158:         end
1159:       end
new(attributes = nil) {|self if block_given?| ...}

New objects can be instantiated as either empty (pass no construction parameter) or pre-set with attributes but not yet saved (pass a hash with key names matching the associated table column names). In both instances, valid attribute keys are determined by the column names of the associated table — hence you can‘t have attributes that aren‘t part of the table columns.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1921
1921:       def initialize(attributes = nil)
1922:         @attributes = attributes_from_column_definition
1923:         @attributes_cache = {}
1924:         @new_record = true
1925:         ensure_proper_type
1926:         self.attributes = attributes unless attributes.nil?
1927:         self.class.send(:scope, :create).each { |att,value| self.send("#{att}=", value) } if self.class.send(:scoped?, :create)
1928:         result = yield self if block_given?
1929:         callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
1930:         result
1931:       end
primary_key()

Defines the primary key field — can be overridden in subclasses. Overwriting will negate any effect of the primary_key_prefix_type setting, though.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 955
955:       def primary_key
956:         reset_primary_key
957:       end
readonly_attributes()

Returns an array of all the attributes that have been specified as readonly.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 868
868:        def readonly_attributes
869:          read_inheritable_attribute("attr_readonly")
870:        end
remove_connection(klass=self)

Remove the connection for this class. This will close the active connection and the defined connection (if they exist). The result can be used as an argument for establish_connection, for easily re-establishing the connection.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 276
276:     def self.remove_connection(klass=self)
277:       spec = @@defined_connections[klass.name]
278:       konn = active_connections[klass.name]
279:       @@defined_connections.delete_if { |key, value| value == spec }
280:       active_connections.delete_if { |key, value| value == konn }
281:       konn.disconnect! if konn
282:       spec.config if spec
283:     end
require_mysql()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 47
47:     def self.require_mysql
48:       # Include the MySQL driver if one hasn't already been loaded
49:       unless defined? Mysql
50:         begin
51:           require_library_or_gem 'mysql'
52:         rescue LoadError => cannot_require_mysql
53:           # Use the bundled Ruby/MySQL driver if no driver is already in place
54:           begin
55:             ActiveRecord::Base.logger.info(
56:               "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " +
57:               "Please install the C-based MySQL library instead (gem install mysql)."
58:             ) if ActiveRecord::Base.logger
59:
60:             require 'active_record/vendor/mysql'
61:           rescue LoadError
62:             raise cannot_require_mysql
63:           end
64:         end
65:       end
66:
67:       # Define Mysql::Result.all_hashes
68:       MysqlCompat.define_all_hashes_method!
69:     end
reset_column_information()

Resets all the cached information about columns, which will cause them to be reloaded on the next request.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1117
1117:       def reset_column_information
1118:         generated_methods.each { |name| undef_method(name) }
1119:         @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil
1120:       end
serialize(attr_name, class_name = Object)

If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on retrieval or SerializationTypeMismatch will be raised.

Options

attr_name The field name that should be serialized class_name Optional, class name that the object type should be equal to

Example

  # Serialize a preferences attribute
  class User
    serialize :preferences
  end

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 887
887:       def serialize(attr_name, class_name = Object)
888:         serialized_attributes[attr_name.to_s] = class_name
889:       end
serialized_attributes()

Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 892
892:       def serialized_attributes
893:         read_inheritable_attribute("attr_serialized") or write_inheritable_attribute("attr_serialized", {})
894:       end
set_inheritance_column(value = nil, &block)

Sets the name of the inheritance column to use to the given value, or (if the value # is nil or false) to the value returned by the given block.

Example:

  class Project < ActiveRecord::Base
    set_inheritance_column do
      original_inheritance_column + "_id"
    end
  end

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1027
1027:       def set_inheritance_column(value = nil, &block)
1028:         define_attr_method :inheritance_column, value, &block
1029:       end
set_primary_key(value = nil, &block)

Sets the name of the primary key column to use to the given value, or (if the value is nil or false) to the value returned by the given block.

Example:

  class Project < ActiveRecord::Base
    set_primary_key "sysid"
  end

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1011
1011:       def set_primary_key(value = nil, &block)
1012:         define_attr_method :primary_key, value, &block
1013:       end
set_sequence_name(value = nil, &block)

Sets the name of the sequence to use when generating ids to the given value, or (if the value is nil or false) to the value returned by the given block. This is required for Oracle and is useful for any database which relies on sequences for primary key generation.

If a sequence name is not explicitly set when using Oracle or Firebird, it will default to the commonly used pattern of: #{table_name}_seq

If a sequence name is not explicitly set when using PostgreSQL, it will discover the sequence corresponding to your primary key for you.

Example:

  class Project < ActiveRecord::Base
    set_sequence_name "projectseq"   # default would have been "project_seq"
  end

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1048
1048:       def set_sequence_name(value = nil, &block)
1049:         define_attr_method :sequence_name, value, &block
1050:       end
set_table_name(value = nil, &block)

Sets the table name to use to the given value, or (if the value is nil or false) to the value returned by the given block.

Example:

  class Project < ActiveRecord::Base
    set_table_name "project"
  end

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 997
997:       def set_table_name(value = nil, &block)
998:         define_attr_method :table_name, value, &block
999:       end
silence() {|| ...}

Silences the logger for the duration of the block.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1196
1196:       def silence
1197:         old_logger_level, logger.level = logger.level, Logger::ERROR if logger
1198:         yield
1199:       ensure
1200:         logger.level = old_logger_level if logger
1201:       end
table_exists?()

Indicates whether the table associated with this class exists

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1062
1062:       def table_exists?
1063:         if connection.respond_to?(:tables)
1064:           connection.tables.include? table_name
1065:         else
1066:           # if the connection adapter hasn't implemented tables, there are two crude tests that can be
1067:           # used - see if getting column info raises an error, or if the number of columns returned is zero
1068:           begin
1069:             reset_column_information
1070:             columns.size > 0
1071:           rescue ActiveRecord::StatementInvalid
1072:             false
1073:           end
1074:         end
1075:       end
table_name()

Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.

Nested classes are given table names prefixed by the singular form of the parent‘s table name. Enclosing modules are not considered. Examples:

  class Invoice < ActiveRecord::Base; end;
  file                  class               table_name
  invoice.rb            Invoice             invoices

  class Invoice < ActiveRecord::Base; class Lineitem < ActiveRecord::Base; end; end;
  file                  class               table_name
  invoice.rb            Invoice::Lineitem   invoice_lineitems

  module Invoice; class Lineitem < ActiveRecord::Base; end; end;
  file                  class               table_name
  invoice/lineitem.rb   Invoice::Lineitem   lineitems

Additionally, the class-level table_name_prefix is prepended and the table_name_suffix is appended. So if you have "myapp_" as a prefix, the table name guess for an Invoice class becomes "myapp_invoices". Invoice::Lineitem becomes "myapp_invoice_lineitems".

You can also overwrite this class method to allow for unguessable links, such as a Mouse class with a link to a "mice" table. Example:

  class Mouse < ActiveRecord::Base
    set_table_name "mice"
  end

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 928
928:       def table_name
929:         reset_table_name
930:       end
update(id, attributes)

Updates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.

Options

id This should be the id or an array of ids to be updated attributes This should be a Hash of attributes to be set on the object, or an array of Hashes.

Examples

  # Updating one record:
  Person.update(15, {:user_name => 'Samuel', :group => 'expert'})

  # Updating multiple records:
  people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
  Person.update(people.keys, people.values)

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 593
593:       def update(id, attributes)
594:         if id.is_a?(Array)
595:           idx = -1
596:           id.collect { |id| idx += 1; update(id, attributes[idx]) }
597:         else
598:           object = find(id)
599:           object.update_attributes(attributes)
600:           object
601:         end
602:       end
update_all(updates, conditions = nil, options = {})

Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied.

Options

updates A String of column and value pairs that will be set on any records that match conditions conditions An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].

              See conditions in the intro for more info.

options Additional options are :limit and/or :order, see the examples for usage.

Examples

  # Update all billing objects with the 3 different attributes given
  Billing.update_all( "category = 'authorized', approved = 1, author = 'David'" )

  # Update records that match our conditions
  Billing.update_all( "author = 'David'", "title LIKE '%Rails%'" )

  # Update records that match our conditions but limit it to 5 ordered by date
  Billing.update_all( "author = 'David'", "title LIKE '%Rails%'",
                        :order => 'created_at', :limit => 5 )

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 670
670:       def update_all(updates, conditions = nil, options = {})
671:         sql  = "UPDATE #{table_name} SET #{sanitize_sql_for_assignment(updates)} "
672:         scope = scope(:find)
673:         add_conditions!(sql, conditions, scope)
674:         add_order!(sql, options[:order], scope)
675:         add_limit!(sql, options, scope)
676:         connection.update(sql, "#{name} Update")
677:       end
update_counters(id, counters)

A generic "counter updater" implementation, intended primarily to be used by increment_counter and decrement_counter, but which may also be useful on its own. It simply does a direct SQL update for the record with the given ID, altering the given hash of counters by the amount given by the corresponding value:

Options

id The id of the object you wish to update a counter on counters An Array of Hashes containing the names of the fields

            to update as keys and the amount to update the field by as
            values

Examples

  # For the Post with id of 5, decrement the comment_count by 1, and
  # increment the action_count by 1
  Post.update_counters 5, :comment_count => -1, :action_count => 1
  # Executes the following SQL:
  # UPDATE posts
  #    SET comment_count = comment_count - 1,
  #        action_count = action_count + 1
  #  WHERE id = 5

[ show source ]

     # File activerecord/lib/active_record/base.rb, line 757
757:       def update_counters(id, counters)
758:         updates = counters.inject([]) { |list, (counter_name, increment)|
759:           sign = increment < 0 ? "-" : "+"
760:           list << "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} #{sign} #{increment.abs}"
761:         }.join(", ")
762:         update_all(updates, "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}")
763:       end
Protected Class methods
class_of_active_record_descendant(klass)

Returns the class descending directly from ActiveRecord in the inheritance hierarchy.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1755
1755:         def class_of_active_record_descendant(klass)
1756:           if klass.superclass == Base || klass.superclass.abstract_class?
1757:             klass
1758:           elsif klass.superclass.nil?
1759:             raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
1760:           else
1761:             class_of_active_record_descendant(klass.superclass)
1762:           end
1763:         end
compute_type(type_name)

Returns the class type of the record using the current module as a prefix. So descendents of MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1745
1745:         def compute_type(type_name)
1746:           modularized_name = type_name_with_module(type_name)
1747:           begin
1748:             class_eval(modularized_name, __FILE__, __LINE__)
1749:           rescue NameError
1750:             class_eval(type_name, __FILE__, __LINE__)
1751:           end
1752:         end
sanitize_sql_array(ary)

Accepts an array of conditions. The array has each value sanitized and interpolated into the sql statement.

  ["name='%s' and group_id='%s'", "foo'bar", 4]  returns  "name='foo''bar' and group_id='4'"

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1835
1835:         def sanitize_sql_array(ary)
1836:           statement, *values = ary
1837:           if values.first.is_a?(Hash) and statement =~ /:\w+/
1838:             replace_named_bind_variables(statement, values.first)
1839:           elsif statement.include?('?')
1840:             replace_bind_variables(statement, values)
1841:           else
1842:             statement % values.collect { |value| connection.quote_string(value.to_s) }
1843:           end
1844:         end
sanitize_sql_for_assignment(assignments)

Accepts an array, hash, or string of sql conditions and sanitizes them into a valid SQL fragment for a SET clause.

  { :name => nil, :group_id => 4 }  returns "name = NULL , group_id='4'"

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1787
1787:         def sanitize_sql_for_assignment(assignments)
1788:           case assignments
1789:             when Array; sanitize_sql_array(assignments)
1790:             when Hash;  sanitize_sql_hash_for_assignment(assignments)
1791:             else        assignments
1792:           end
1793:         end
sanitize_sql_for_conditions(condition)

Accepts an array, hash, or string of sql conditions and sanitizes them into a valid SQL fragment for a WHERE clause.

  ["name='%s' and group_id='%s'", "foo'bar", 4]  returns  "name='foo''bar' and group_id='4'"
  { :name => "foo'bar", :group_id => 4 }  returns "name='foo''bar' and group_id='4'"
  "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1775
1775:         def sanitize_sql_for_conditions(condition)
1776:           case condition
1777:             when Array; sanitize_sql_array(condition)
1778:             when Hash;  sanitize_sql_hash_for_conditions(condition)
1779:             else        condition
1780:           end
1781:         end
sanitize_sql_hash_for_assignment(attrs)

Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.

  { :status => nil, :group_id => 1 }
    # => "status = NULL , group_id = 1"

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1826
1826:         def sanitize_sql_hash_for_assignment(attrs)
1827:           conditions = attrs.map do |attr, value|
1828:             "#{connection.quote_column_name(attr)} = #{quote_bound_value(value)}"
1829:           end.join(', ')
1830:         end
sanitize_sql_hash_for_conditions(attrs)

Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.

  { :name => "foo'bar", :group_id => 4 }
    # => "name='foo''bar' and group_id= 4"
  { :status => nil, :group_id => [1,2,3] }
    # => "status IS NULL and group_id IN (1,2,3)"
  { :age => 13..18 }
    # => "age BETWEEN 13 AND 18"
  { 'other_records.id' => 7 }
    # => "`other_records`.`id` = 7"

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1804
1804:         def sanitize_sql_hash_for_conditions(attrs)
1805:           conditions = attrs.map do |attr, value|
1806:             attr = attr.to_s
1807:
1808:             # Extract table name from qualified attribute names.
1809:             if attr.include?('.')
1810:               table_name, attr = attr.split('.', 2)
1811:               table_name = connection.quote_table_name(table_name)
1812:             else
1813:               table_name = quoted_table_name
1814:             end
1815:
1816:             "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
1817:           end.join(' AND ')
1818:
1819:           replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
1820:         end
with_exclusive_scope(method_scoping = {}, &block)

Works like with_scope, but discards any nested properties.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1700
1700:         def with_exclusive_scope(method_scoping = {}, &block)
1701:           with_scope(method_scoping, :overwrite, &block)
1702:         end
with_scope(method_scoping = {}, action = :merge) {|| ...}

Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. method_name may be :find or :create. :find parameters may include the :conditions, :joins, :include, :offset, :limit, and :readonly options. :create parameters are an attributes hash.

  class Article < ActiveRecord::Base
    def self.create_with_scope
      with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
        find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
        a = create(1)
        a.blog_id # => 1
      end
    end
  end

In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of :conditions and :include options in :find, which are merged.

  class Article < ActiveRecord::Base
    def self.find_with_scope
      with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
        with_scope(:find => { :limit => 10})
          find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
        end
        with_scope(:find => { :conditions => "author_id = 3" })
          find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
        end
      end
    end
  end

You can ignore any previous scopings by using the with_exclusive_scope method.

  class Article < ActiveRecord::Base
    def self.find_with_exclusive_scope
      with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do
        with_exclusive_scope(:find => { :limit => 10 })
          find(:all) # => SELECT * from articles LIMIT 10
        end
      end
    end
  end

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1648
1648:         def with_scope(method_scoping = {}, action = :merge, &block)
1649:           method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
1650:
1651:           # Dup first and second level of hash (method and params).
1652:           method_scoping = method_scoping.inject({}) do |hash, (method, params)|
1653:             hash[method] = (params == true) ? params : params.dup
1654:             hash
1655:           end
1656:
1657:           method_scoping.assert_valid_keys([ :find, :create ])
1658:
1659:           if f = method_scoping[:find]
1660:             f.assert_valid_keys(VALID_FIND_OPTIONS)
1661:             set_readonly_option! f
1662:           end
1663:
1664:           # Merge scopings
1665:           if action == :merge && current_scoped_methods
1666:             method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)|
1667:               case hash[method]
1668:                 when Hash
1669:                   if method == :find
1670:                     (hash[method].keys + params.keys).uniq.each do |key|
1671:                       merge = hash[method][key] && params[key] # merge if both scopes have the same key
1672:                       if key == :conditions && merge
1673:                         hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ")
1674:                       elsif key == :include && merge
1675:                         hash[method][key] = merge_includes(hash[method][key], params[key]).uniq
1676:                       else
1677:                         hash[method][key] = hash[method][key] || params[key]
1678:                       end
1679:                     end
1680:                   else
1681:                     hash[method] = params.merge(hash[method])
1682:                   end
1683:                 else
1684:                   hash[method] = params
1685:               end
1686:               hash
1687:             end
1688:           end
1689:
1690:           self.scoped_methods << method_scoping
1691:
1692:           begin
1693:             yield
1694:           ensure
1695:             self.scoped_methods.pop
1696:           end
1697:         end
Public Instance methods
==(comparison_object)

Returns true if the comparison_object is the same object, or is of the same type and has the same id.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2187
2187:       def ==(comparison_object)
2188:         comparison_object.equal?(self) ||
2189:           (comparison_object.instance_of?(self.class) &&
2190:             comparison_object.id == id &&
2191:             !comparison_object.new_record?)
2192:       end
[](attr_name)

Returns the value of the attribute identified by attr_name after it has been typecast (for example, "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). (Alias for the protected read_attribute method).

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2094
2094:       def [](attr_name)
2095:         read_attribute(attr_name)
2096:       end
[]=(attr_name, value)

Updates the attribute identified by attr_name with the specified value. (Alias for the protected write_attribute method).

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2100
2100:       def []=(attr_name, value)
2101:         write_attribute(attr_name, value)
2102:       end
attribute_for_inspect(attr_name)

Format attributes nicely for inspect.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2152
2152:       def attribute_for_inspect(attr_name)
2153:         value = read_attribute(attr_name)
2154:
2155:         if value.is_a?(String) && value.length > 50
2156:           "#{value[0..50]}...".inspect
2157:         elsif value.is_a?(Date) || value.is_a?(Time)
2158:           %("#{value.to_s(:db)}")
2159:         else
2160:           value.inspect
2161:         end
2162:       end
attribute_names()

Returns an array of names for the attributes available on this object sorted alphabetically.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2177
2177:       def attribute_names
2178:         @attributes.keys.sort
2179:       end
attribute_present?(attribute)

Returns true if the specified attribute has been set by the user or by a database load and is neither nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings).

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2166
2166:       def attribute_present?(attribute)
2167:         value = read_attribute(attribute)
2168:         !value.blank?
2169:       end
attributes(options = nil)

Returns a hash of all the attributes with their names as keys and clones of their objects as values.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2126
2126:       def attributes(options = nil)
2127:         attributes = clone_attributes :read_attribute
2128:
2129:         if options.nil?
2130:           attributes
2131:         else
2132:           if except = options[:except]
2133:             except = Array(except).collect { |attribute| attribute.to_s }
2134:             except.each { |attribute_name| attributes.delete(attribute_name) }
2135:             attributes
2136:           elsif only = options[:only]
2137:             only = Array(only).collect { |attribute| attribute.to_s }
2138:             attributes.delete_if { |key, value| !only.include?(key) }
2139:             attributes
2140:           else
2141:             raise ArgumentError, "Options does not specify :except or :only (#{options.keys.inspect})"
2142:           end
2143:         end
2144:       end
attributes=(new_attributes, guard_protected_attributes = true)

Allows you to set all the attributes at once by passing in a hash with keys matching the attribute names (which again matches the column names). Sensitive attributes can be protected from this form of mass-assignment by using the attr_protected macro. Or you can alternatively specify which attributes can be accessed with the attr_accessible macro. Then all the attributes not included in that won‘t be allowed to be mass-assigned.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2109
2109:       def attributes=(new_attributes, guard_protected_attributes = true)
2110:         return if new_attributes.nil?
2111:         attributes = new_attributes.dup
2112:         attributes.stringify_keys!
2113:
2114:         multi_parameter_attributes = []
2115:         attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
2116:
2117:         attributes.each do |k, v|
2118:           k.include?("(") ? multi_parameter_attributes << [ k, v ] : send(k + "=", v)
2119:         end
2120:
2121:         assign_multiparameter_attributes(multi_parameter_attributes)
2122:       end
attributes_before_type_cast()

Returns a hash of cloned attributes before typecasting and deserialization.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2147
2147:       def attributes_before_type_cast
2148:         clone_attributes :read_attribute_before_type_cast
2149:       end
becomes(klass)

Returns an instance of the specified klass with the attributes of the current record. This is mostly useful in relation to single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record identification in Action Pack to allow, say, Client < Company to do something like render :partial => @client.becomes(Company) to render that instance using the companies/company partial instead of clients/client.

Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either instance will affect the other.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2015
2015:       def becomes(klass)
2016:         returning klass.new do |became|
2017:           became.instance_variable_set("@attributes", @attributes)
2018:           became.instance_variable_set("@attributes_cache", @attributes_cache)
2019:           became.instance_variable_set("@new_record", new_record?)
2020:         end
2021:       end
clone()

Returns a clone of the record that hasn‘t been assigned an id yet and is treated as a new record. Note that this is a "shallow" clone: it copies the object‘s attributes only, not its associations. The extent of a "deep" clone is application-specific and is therefore left to the application to implement according to its need.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2000
2000:       def clone
2001:         attrs = self.attributes_before_type_cast
2002:         attrs.delete(self.class.primary_key)
2003:         record = self.class.new
2004:         record.send :instance_variable_set, '@attributes', attrs
2005:         record
2006:       end
column_for_attribute(name)

Returns the column object for the named attribute.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2182
2182:       def column_for_attribute(name)
2183:         self.class.columns_hash[name.to_s]
2184:       end
connection()

Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work that isn‘t easily done without going straight to SQL.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 173
173:     def connection
174:       self.class.connection
175:     end
decrement(attribute)

Initializes the attribute to zero if nil and subtracts one. Only makes sense for number-based attributes. Returns self.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2057
2057:       def decrement(attribute)
2058:         self[attribute] ||= 0
2059:         self[attribute] -= 1
2060:         self
2061:       end
decrement!(attribute)

Decrements the attribute and saves the record.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2064
2064:       def decrement!(attribute)
2065:         decrement(attribute).update_attribute(attribute, self[attribute])
2066:       end
destroy()

Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can‘t be persisted).

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1983
1983:       def destroy
1984:         unless new_record?
1985:           connection.delete "DELETE FROM \#{self.class.quoted_table_name}\nWHERE \#{connection.quote_column_name(self.class.primary_key)} = \#{quoted_id}\n", "#{self.class.name} Destroy"
1986:         end
1987:
1988:         freeze
1989:       end
eql?(comparison_object)

Delegates to ==

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2195
2195:       def eql?(comparison_object)
2196:         self == (comparison_object)
2197:       end
freeze()

Freeze the attributes hash such that associations are still accessible, even on destroyed records.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2206
2206:       def freeze
2207:         @attributes.freeze; self
2208:       end
frozen?()

Returns true if the attributes hash has been frozen.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2211
2211:       def frozen?
2212:         @attributes.frozen?
2213:       end
has_attribute?(attr_name)

Returns true if the given attribute is in the attributes hash

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2172
2172:       def has_attribute?(attr_name)
2173:         @attributes.has_key?(attr_name.to_s)
2174:       end
hash()

Delegates to id in order to allow two records of the same type and id to work with something like:

  [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2201
2201:       def hash
2202:         id.hash
2203:       end
id()

A model instance‘s primary key is always available as model.id whether you name it the default ‘id’ or set it to something else.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1935
1935:       def id
1936:         attr_name = self.class.primary_key
1937:         column = column_for_attribute(attr_name)
1938:
1939:         self.class.send(:define_read_method, :id, attr_name, column)
1940:         # now that the method exists, call it
1941:         self.send attr_name.to_sym
1942:
1943:       end
id=(value)

Sets the primary ID.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1960
1960:       def id=(value)
1961:         write_attribute(self.class.primary_key, value)
1962:       end
increment(attribute)

Initializes the attribute to zero if nil and adds one. Only makes sense for number-based attributes. Returns self.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2045
2045:       def increment(attribute)
2046:         self[attribute] ||= 0
2047:         self[attribute] += 1
2048:         self
2049:       end
increment!(attribute)

Increments the attribute and saves the record.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2052
2052:       def increment!(attribute)
2053:         increment(attribute).update_attribute(attribute, self[attribute])
2054:       end
inspect()

Returns the contents of the record as a nicely formatted string.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2227
2227:       def inspect
2228:         attributes_as_nice_string = self.class.column_names.collect { |name|
2229:           if has_attribute?(name) || new_record?
2230:             "#{name}: #{attribute_for_inspect(name)}"
2231:           end
2232:         }.compact.join(", ")
2233:         "#<#{self.class} #{attributes_as_nice_string}>"
2234:       end
new_record?()

Returns true if this object hasn‘t been saved yet — that is, a record for the object doesn‘t exist yet.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1965
1965:       def new_record?
1966:         @new_record
1967:       end
readonly!()

Marks this record as read only.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2222
2222:       def readonly!
2223:         @readonly = true
2224:       end
readonly?()

Returns true if the record is read only. Records loaded through joins with piggy-back attributes will be marked as read only since they cannot be saved.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2217
2217:       def readonly?
2218:         @readonly == true
2219:       end
reload(options = nil)

Reloads the attributes of this object from the database. The optional options argument is passed to find when reloading so you may do e.g. record.reload(:lock => true) to reload the same record with an exclusive row lock.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2083
2083:       def reload(options = nil)
2084:         clear_aggregation_cache
2085:         clear_association_cache
2086:         @attributes.update(self.class.find(self.id, options).instance_variable_get('@attributes'))
2087:         @attributes_cache = {}
2088:         self
2089:       end
save()
  • No record exists: Creates a new record with values matching those of the object attributes.
  • A record does exist: Updates the record with values matching those of the object attributes.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1971
1971:       def save
1972:         create_or_update
1973:       end
save!()

Attempts to save the record, but instead of just returning false if it couldn‘t happen, it raises a RecordNotSaved exception

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1977
1977:       def save!
1978:         create_or_update || raise(RecordNotSaved)
1979:       end
to_param()

Enables Active Record objects to be used as URL parameters in Action Pack automatically.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 1946
1946:       def to_param
1947:         # We can't use alias_method here, because method 'id' optimizes itself on the fly.
1948:         (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
1949:       end
toggle(attribute)

Turns an attribute that‘s currently true into false and vice versa. Returns self.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2069
2069:       def toggle(attribute)
2070:         self[attribute] = !send("#{attribute}?")
2071:         self
2072:       end
toggle!(attribute)

Toggles the attribute and saves the record.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2075
2075:       def toggle!(attribute)
2076:         toggle(attribute).update_attribute(attribute, self[attribute])
2077:       end
update_attribute(name, value)

Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. Note: This method is overwritten by the Validation module that‘ll make sure that updates made with this method aren‘t subjected to validation checks. Hence, attributes can be updated even if the full object isn‘t valid.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2026
2026:       def update_attribute(name, value)
2027:         send(name.to_s + '=', value)
2028:         save
2029:       end
update_attributes(attributes)

Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will fail and false will be returned.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2033
2033:       def update_attributes(attributes)
2034:         self.attributes = attributes
2035:         save
2036:       end
update_attributes!(attributes)

Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.

[ show source ]

      # File activerecord/lib/active_record/base.rb, line 2039
2039:       def update_attributes!(attributes)
2040:         self.attributes = attributes
2041:         save!
2042:       end


Class: ActiveRecord::ActiveRecordError

Class
ActiveRecord::ActiveRecordError
In: | activerecord/lib/active_record/base.rb
Parent: | StandardError

Generic ActiveRecord exception class.


Class: ActiveRecord::AdapterNotFound

Class
ActiveRecord::AdapterNotFound
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically.


Class: ActiveRecord::AdapterNotSpecified

Class
ActiveRecord::AdapterNotSpecified
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field).


Module: ActiveRecord::Aggregations::ClassMethods

Module
ActiveRecord::Aggregations::ClassMethods
In: activerecord/lib/active_record/aggregations.rb

Active Record implements aggregation through a macro-like class method called composed_of for representing attributes as value objects. It expresses relationships like "Account [is] composed of Money [among other things]" or "Person [is] composed of [an] address". Each call to the macro adds a description of how the value objects are created from the attributes of the entity object (when the entity is initialized either as a new object or from finding an existing object) and how it can be turned back into attributes (when the entity is saved to the database). Example:

  class Customer < ActiveRecord::Base
    composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
    composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
  end

The customer class now has the following methods to manipulate the value objects:

  • Customer#balance, Customer#balance=(money)
  • Customer#address, Customer#address=(address)

These methods will operate with value objects like the ones described below:

 class Money
   include Comparable
   attr_reader :amount, :currency
   EXCHANGE_RATES = { "USD_TO_DKK" => 6 }

   def initialize(amount, currency = "USD")
     @amount, @currency = amount, currency
   end

   def exchange_to(other_currency)
     exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor
     Money.new(exchanged_amount, other_currency)
   end

   def ==(other_money)
     amount == other_money.amount && currency == other_money.currency
   end

   def <=>(other_money)
     if currency == other_money.currency
       amount <=> amount
     else
       amount <=> other_money.exchange_to(currency).amount
     end
   end
 end

 class Address
   attr_reader :street, :city
   def initialize(street, city)
     @street, @city = street, city
   end

   def close_to?(other_address)
     city == other_address.city
   end

   def ==(other_address)
     city == other_address.city && street == other_address.street
   end
 end

Now it‘s possible to access attributes from the database through the value objects instead. If you choose to name the composition the same as the attribute‘s name, it will be the only way to access that attribute. That‘s the case with our balance attribute. You interact with the value objects just like you would any other attribute, though:

  customer.balance = Money.new(20)     # sets the Money value object and the attribute
  customer.balance                     # => Money value object
  customer.balance.exchanged_to("DKK") # => Money.new(120, "DKK")
  customer.balance > Money.new(10)     # => true
  customer.balance == Money.new(20)    # => true
  customer.balance < Money.new(5)      # => false

Value objects can also be composed of multiple attributes, such as the case of Address. The order of the mappings will determine the order of the parameters. Example:

  customer.address_street = "Hyancintvej"
  customer.address_city   = "Copenhagen"
  customer.address        # => Address.new("Hyancintvej", "Copenhagen")
  customer.address = Address.new("May Street", "Chicago")
  customer.address_street # => "May Street"
  customer.address_city   # => "Chicago"

Writing value objects

Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects.

It‘s also important to treat the value objects as immutable. Don‘t allow the Money object to have its amount changed after creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that returns a new value object instead of changing its own values. Active Record won‘t persist value objects that have been changed through means other than the writer method.

The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to change it afterwards will result in a TypeError.

Read more about value objects on c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects immutable on c2.com/cgi/wiki?ValueObjectsShouldBeImmutable

Methods
  • composed_of
Public Instance methods
composed_of(part_id, options = {}, &block)

Adds reader and writer methods for manipulating a value object: composed_of :address adds address and address=(new_address) methods.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can‘t be inferred from the part id. So composed_of :address will by default be linked to the Address class, but if the real class name is CompanyAddress, you‘ll have to specify it with this option.
  • :mapping - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name to a constructor parameter on the value class.
  • :allow_nil - specifies that the aggregate object will not be instantiated when all mapped attributes are nil. Setting the aggregate class to nil has the effect of writing nil to all mapped attributes. This defaults to false.

An optional block can be passed to convert the argument that is passed to the writer method into an instance of :class_name. The block will only be called if the argument is not already an instance of :class_name.

Option examples:

  composed_of :temperature, :mapping => %w(reading celsius)
  composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) {|balance| balance.to_money }
  composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
  composed_of :gps_location
  composed_of :gps_location, :allow_nil => true

[ show source ]

     # File activerecord/lib/active_record/aggregations.rb, line 135
135:       def composed_of(part_id, options = {}, &block)
136:         options.assert_valid_keys(:class_name, :mapping, :allow_nil)
137:
138:         name        = part_id.id2name
139:         class_name  = options[:class_name] || name.camelize
140:         mapping     = options[:mapping]    || [ name, name ]
141:         mapping     = [ mapping ] unless mapping.first.is_a?(Array)
142:         allow_nil   = options[:allow_nil]  || false
143:
144:         reader_method(name, class_name, mapping, allow_nil)
145:         writer_method(name, class_name, mapping, allow_nil, block)
146:
147:         create_reflection(:composed_of, part_id, options, self)
148:       end


Class: ActiveRecord::AssociationTypeMismatch

Class
ActiveRecord::AssociationTypeMismatch
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when object assigned to association is of incorrect type.

Example:

class Ticket < ActiveRecord::Base

  has_many :patches

end

class Patch < ActiveRecord::Base

  belongs_to :ticket

end

and somewhere in the code:

@ticket.patches << Comment.new(:content => "Please attach tests to your patch.") @ticket.save


Module: ActiveRecord::Associations::ClassMethods

Module
ActiveRecord::Associations::ClassMethods
In: activerecord/lib/active_record/associations.rb

Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby‘s own attr* methods. Example:

  class Project < ActiveRecord::Base
    belongs_to              :portfolio
    has_one                 :project_manager
    has_many                :milestones
    has_and_belongs_to_many :categories
  end

The project class now has the following methods (and more) to ease the traversal and manipulation of its relationships:

  • Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?
  • Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,
  • Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone), Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.find(:all, options), Project#milestones.build, Project#milestones.create
  • Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1), Project#categories.delete(category1)

A word of warning

Don‘t create associations that have the same name as instance methods of ActiveRecord::Base. Since the association adds a method with that name to its model, it will override the inherited method and break things. For instance, attributes and connection would be bad choices for association names.

Auto-generated methods

Singular associations (one-to-one)

                                    |            |  belongs_to  |
  generated methods                 | belongs_to | :polymorphic | has_one
  ----------------------------------+------------+--------------+---------
  #other                            |     X      |      X       |    X
  #other=(other)                    |     X      |      X       |    X
  #build_other(attributes={})       |     X      |              |    X
  #create_other(attributes={})      |     X      |              |    X
  #other.create!(attributes={})     |            |              |    X
  #other.nil?                       |     X      |      X       |

Collection associations (one-to-many / many-to-many)

                                    |       |          | has_many
  generated methods                 | habtm | has_many | :through
  ----------------------------------+-------+----------+----------
  #others                           |   X   |    X     |    X
  #others=(other,other,...)         |   X   |    X     |
  #other_ids                        |   X   |    X     |    X
  #other_ids=(id,id,...)            |   X   |    X     |
  #others<<                         |   X   |    X     |    X
  #others.push                      |   X   |    X     |    X
  #others.concat                    |   X   |    X     |    X
  #others.build(attributes={})      |   X   |    X     |    X
  #others.create(attributes={})     |   X   |    X     |
  #others.create!(attributes={})    |   X   |    X     |    X
  #others.size                      |   X   |    X     |    X
  #others.length                    |   X   |    X     |    X
  #others.count                     |       |    X     |    X
  #others.sum(args*,&block)         |   X   |    X     |    X
  #others.empty?                    |   X   |    X     |    X
  #others.clear                     |   X   |    X     |
  #others.delete(other,other,...)   |   X   |    X     |    X
  #others.delete_all                |   X   |    X     |
  #others.destroy_all               |   X   |    X     |    X
  #others.find(*args)               |   X   |    X     |    X
  #others.find_first                |   X   |          |
  #others.uniq                      |   X   |    X     |
  #others.reset                     |   X   |    X     |    X

Cardinality and associations

ActiveRecord associations can be used to describe relations with one-to-one, one-to-many and many-to-many cardinality. Each model uses an association to describe its role in the relation. In each case, the belongs_to association is used in the model that has the foreign key.

One-to-one

Use has_one in the base, and belongs_to in the associated model.

  class Employee < ActiveRecord::Base
    has_one :office
  end
  class Office < ActiveRecord::Base
    belongs_to :employee    # foreign key - employee_id
  end

One-to-many

Use has_many in the base, and belongs_to in the associated model.

  class Manager < ActiveRecord::Base
    has_many :employees
  end
  class Employee < ActiveRecord::Base
    belongs_to :manager     # foreign key - manager_id
  end

Many-to-many

There are two ways to build a many-to-many relationship.

The first way uses a has_many association with the :through option and a join model, so there are two stages of associations.

  class Assignment < ActiveRecord::Base
    belongs_to :programmer  # foreign key - programmer_id
    belongs_to :project     # foreign key - project_id
  end
  class Programmer < ActiveRecord::Base
    has_many :assignments
    has_many :projects, :through => :assignments
  end
  class Project < ActiveRecord::Base
    has_many :assignments
    has_many :programmers, :through => :assignments
  end

For the second way, use has_and_belongs_to_many in both models. This requires a join table that has no corresponding model or primary key.

  class Programmer < ActiveRecord::Base
    has_and_belongs_to_many :projects       # foreign keys in the join table
  end
  class Project < ActiveRecord::Base
    has_and_belongs_to_many :programmers    # foreign keys in the join table
  end

Choosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.

Is it a belongs_to or has_one association?

Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class declaring the belongs_to relationship. Example:

  class User < ActiveRecord::Base
    # I reference an account.
    belongs_to :account
  end

  class Account < ActiveRecord::Base
    # One user references me.
    has_one :user
  end

The tables for these classes could look something like:

  CREATE TABLE users (
    id int(11) NOT NULL auto_increment,
    account_id int(11) default NULL,
    name varchar default NULL,
    PRIMARY KEY  (id)
  )

  CREATE TABLE accounts (
    id int(11) NOT NULL auto_increment,
    name varchar default NULL,
    PRIMARY KEY  (id)
  )

Unsaved objects and associations

You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be aware of, mostly involving the saving of associated objects.

One-to-one associations

  • Assigning an object to a has_one association automatically saves that object and the object being replaced (if there is one), in order to update their primary keys - except if the parent object is unsaved (new_record? == true).
  • If either of these saves fail (due to one of the objects being invalid) the assignment statement returns false and the assignment is cancelled.
  • If you wish to assign an object to a has_one association without saving it, use the association.build method (documented below).
  • Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does not save the parent either.

Collections

  • Adding an object to a collection (has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object (the owner of the collection) is not yet stored in the database.
  • If saving any of the objects being added to a collection (via push or similar) fails, then push returns false.
  • You can add an object to a collection without automatically saving it by using the collection.build method (documented below).
  • All unsaved (new_record? == true) members of the collection are automatically saved when the parent is saved.

Association callbacks

Similar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get triggered when you add an object to or remove an object from an association collection. Example:

  class Project
    has_and_belongs_to_many :developers, :after_add => :evaluate_velocity

    def evaluate_velocity(developer)
      ...
    end
  end

It‘s possible to stack callbacks by passing them as an array. Example:

  class Project
    has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
  end

Possible callbacks are: before_add, after_add, before_remove and after_remove.

Should any of the before_add callbacks throw an exception, the object does not get added to the collection. Same with the before_remove callbacks; if an exception is thrown the object doesn‘t get removed.

Association extensions

The proxy objects that control the access to associations can be extended through anonymous modules. This is especially beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association. Example:

  class Account < ActiveRecord::Base
    has_many :people do
      def find_or_create_by_name(name)
        first_name, last_name = name.split(" ", 2)
        find_or_create_by_first_name_and_last_name(first_name, last_name)
      end
    end
  end

  person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson")
  person.first_name # => "David"
  person.last_name  # => "Heinemeier Hansson"

If you need to share the same extensions between many associations, you can use a named extension module. Example:

  module FindOrCreateByNameExtension
    def find_or_create_by_name(name)
      first_name, last_name = name.split(" ", 2)
      find_or_create_by_first_name_and_last_name(first_name, last_name)
    end
  end

  class Account < ActiveRecord::Base
    has_many :people, :extend => FindOrCreateByNameExtension
  end

  class Company < ActiveRecord::Base
    has_many :people, :extend => FindOrCreateByNameExtension
  end

If you need to use multiple named extension modules, you can specify an array of modules with the :extend option. In the case of name conflicts between methods in the modules, methods in modules later in the array supercede those earlier in the array. Example:

  class Account < ActiveRecord::Base
    has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
  end

Some extensions can only be made to work with knowledge of the association proxy‘s internals. Extensions can access relevant state using accessors on the association proxy:

  • proxy_owner - Returns the object the association is part of.
  • proxy_reflection - Returns the reflection object that describes the association.
  • proxy_target - Returns the associated object for belongs_to and has_one, or the collection of associated objects for has_many and has_and_belongs_to_many.

Association Join Models

Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This operates similarly to a has_and_belongs_to_many association. The advantage is that you‘re able to add validations, callbacks, and extra attributes on the join model. Consider the following schema:

  class Author < ActiveRecord::Base
    has_many :authorships
    has_many :books, :through => :authorships
  end

  class Authorship < ActiveRecord::Base
    belongs_to :author
    belongs_to :book
  end

  @author = Author.find :first
  @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
  @author.books                              # selects all books by using the Authorship join model

You can also go through a has_many association on the join model:

  class Firm < ActiveRecord::Base
    has_many   :clients
    has_many   :invoices, :through => :clients
  end

  class Client < ActiveRecord::Base
    belongs_to :firm
    has_many   :invoices
  end

  class Invoice < ActiveRecord::Base
    belongs_to :client
  end

  @firm = Firm.find :first
  @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
  @firm.invoices                                   # selects all invoices by going through the Client join model.

Polymorphic Associations

Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they specify an interface that a has_many association must adhere to.

  class Asset < ActiveRecord::Base
    belongs_to :attachable, :polymorphic => true
  end

  class Post < ActiveRecord::Base
    has_many :assets, :as => :attachable         # The :as option specifies the polymorphic interface to use.
  end

  @asset.attachable = @post

This works by using a type column in addition to a foreign key to specify the associated record. In the Asset example, you‘d need an attachable_id integer column and an attachable_type string column.

Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts and member posts that use the posts table for STI. In this case, there must be a type column in the posts table.

  class Asset < ActiveRecord::Base
    belongs_to :attachable, :polymorphic => true

    def attachable_type=(sType)
       super(sType.to_s.classify.constantize.base_class.to_s)
    end
  end

  class Post < ActiveRecord::Base
    # because we store "Post" in attachable_type now :dependent => :destroy will work
    has_many :assets, :as => :attachable, :dependent => :destroy
  end

  class GuestPost < Post
  end

  class MemberPost < Post
  end

Caching

All of the methods are built on a simple caching principle that will keep the result of the last query around unless specifically instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without worrying too much about performance at the first go. Example:

  project.milestones             # fetches milestones from the database
  project.milestones.size        # uses the milestone cache
  project.milestones.empty?      # uses the milestone cache
  project.milestones(true).size  # fetches milestones from the database
  project.milestones             # uses the milestone cache

Eager loading of associations

Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example:

  class Post < ActiveRecord::Base
    belongs_to :author
    has_many   :comments
  end

Consider the following loop using the class above:

  for post in Post.find(:all)
    puts "Post:            " + post.title
    puts "Written by:      " + post.author.name
    puts "Last comment on: " + post.comments.first.created_on
  end

To iterate over these one hundred posts, we‘ll generate 201 database queries. Let‘s first just optimize it for retrieving the author:

  for post in Post.find(:all, :include => :author)

This references the name of the belongs_to association that also used the :author symbol, so the find will now weave in a join something like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101.

We can improve upon the situation further by referencing both associations in the finder with:

  for post in Post.find(:all, :include => [ :author, :comments ])

That‘ll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we‘ll be down to 1 query.

To include a deep hierarchy of associations, use a hash:

  for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ])

That‘ll grab not only all the comments but all their authors and gravatar pictures. You can mix and match symbols, arrays and hashes in any combination to describe the associations you want to load.

All of this power shouldn‘t fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you‘ve reduced the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it‘s no catch-all for performance problems, but it‘s a great way to cut down on the number of queries in a situation as the one described above.

Since the eager loading pulls from multiple tables, you‘ll have to disambiguate any column references in both conditions and orders. So :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the SELECT statement too, the :select option is ignored.

You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich associations" with has_and_belongs_to_many are not a good fit for eager loading.

When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated before the actual model exists.

Table Aliasing

ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended for any more successive uses of the table name.

  Post.find :all, :include => :comments
  # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...
  Post.find :all, :include => :special_comments # STI
  # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment'
  Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
  # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts

Acts as tree example:

  TreeMixin.find :all, :include => :children
  # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
  TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes
  # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
                              LEFT OUTER JOIN parents_mixins ...
  TreeMixin.find :all, :include => {:children => {:parent => :children}}
  # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
                              LEFT OUTER JOIN parents_mixins ...
                              LEFT OUTER JOIN mixins childrens_mixins_2

Has and Belongs to Many join tables use the same idea, but add a _join suffix:

  Post.find :all, :include => :categories
  # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
  Post.find :all, :include => {:categories => :posts}
  # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
                             LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
  Post.find :all, :include => {:categories => {:posts => :categories}}
  # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
                             LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
                             LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts

If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations:

  Post.find :all, :include => :comments, :joins => "inner join comments ..."
  # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
  Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..."
  # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
                             LEFT OUTER JOIN comments special_comments_posts ...
                             INNER JOIN comments ...

Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.

Modules

By default, associations will look for objects within the current module scope. Consider:

  module MyApplication
    module Business
      class Firm < ActiveRecord::Base
         has_many :clients
       end

      class Company < ActiveRecord::Base; end
    end
  end

When Firm#clients is called, it will in turn call MyApplication::Business::Company.find(firm.id). If you want to associate with a class in another module scope, this can be done by specifying the complete class name. Example:

  module MyApplication
    module Business
      class Firm < ActiveRecord::Base; end
    end

    module Billing
      class Account < ActiveRecord::Base
        belongs_to :firm, :class_name => "MyApplication::Business::Firm"
      end
    end
  end

Type safety with ActiveRecord::AssociationTypeMismatch

If you attempt to assign an object to an association that doesn‘t match the inferred or specified :class_name, you‘ll get an ActiveRecord::AssociationTypeMismatch.

Options

All of the association macros can be specialized through options. This makes cases more complex than the simple and guessable ones possible.

Methods
  • belongs_to
  • has_and_belongs_to_many
  • has_many
  • has_one
Public Instance methods
belongs_to(association_id, options = {})

Adds the following methods for retrieval and query for a single associated object for which this object holds an id: association is replaced with the symbol passed as the first argument, so belongs_to :author would add among others author.nil?.

  • association(force_reload = false) - returns the associated object. nil is returned if none is found.
  • association=(associate) - assigns the associate object, extracts the primary key, and sets it as the foreign key.
  • association.nil? - returns true if there is no associated object.
  • build_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved.
  • create_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes, linked to this object through a foreign key, and that has already been saved (if it passed the validation).

Example: A Post class declares belongs_to :author, which will add:

  • Post#author (similar to Author.find(author_id))
  • Post#author=(author) (similar to post.author_id = author.id)
  • Post#author? (similar to post.author == some_author)
  • Post#author.nil?
  • Post#build_author (similar to post.author = Author.new)
  • Post#create_author (similar to post.author = Author.new; post.author.save; post.author)

The declaration can also include an options hash to specialize the behavior of the association.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can‘t be inferred from the association name. So has_one :author will by default be linked to the Author class, but if the real class name is Person, you‘ll have to specify it with this option.
  • :conditions - specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1.
  • :order - specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC
  • :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of the associated class in lower-case and _id suffixed. So a Person class that makes a belongs_to association to a Boss class will use boss_id as the default foreign_key.
  • :counter_cache - caches the number of belonging objects on the associate class through the use of increment_counter and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it‘s destroyed. This requires that a column named #{table_name}_count (such as comments_count for a belonging Comment class) is used on the associate class (such as a Post class). You can also specify a custom counter cache column by providing a column name instead of a true/false value to this option (e.g., :counter_cache => :my_custom_counter.) Note: Specifying a counter_cache will add it to that model‘s list of readonly attributes using attr_readonly.
  • :include - specify second-order associations that should be eager loaded when this object is loaded.
  • :polymorphic - specify this association is a polymorphic association by passing true. Note: If you‘ve enabled the counter cache, then you may want to add the counter cache attribute to the attr_readonly list in the associated classes (e.g. class Post; attr_readonly :comments_count; end).

Option examples:

  belongs_to :firm, :foreign_key => "client_of"
  belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
  belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
             :conditions => 'discounts > #{payments_count}'
  belongs_to :attachable, :polymorphic => true

[ show source ]

     # File activerecord/lib/active_record/associations.rb, line 795
795:       def belongs_to(association_id, options = {})
796:         reflection = create_belongs_to_reflection(association_id, options)
797:
798:         if reflection.options[:polymorphic]
799:           association_accessor_methods(reflection, BelongsToPolymorphicAssociation)
800:
801:           module_eval do
802:             before_save "association = instance_variable_get(\"@\#{reflection.name}\")\nif association && association.target\nif association.new_record?\nassociation.save(true)\nend\n\nif association.updated?\nself[\"\#{reflection.primary_key_name}\"] = association.id\nself[\"\#{reflection.options[:foreign_type]}\"] = association.class.base_class.name.to_s\nend\nend\n"
803:           end
804:         else
805:           association_accessor_methods(reflection, BelongsToAssociation)
806:           association_constructor_method(:build,  reflection, BelongsToAssociation)
807:           association_constructor_method(:create, reflection, BelongsToAssociation)
808:
809:           module_eval do
810:             before_save "association = instance_variable_get(\"@\#{reflection.name}\")\nif !association.nil?\nif association.new_record?\nassociation.save(true)\nend\n\nif association.updated?\nself[\"\#{reflection.primary_key_name}\"] = association.id\nend\nend\n"
811:           end
812:         end
813:
814:         # Create the callbacks to update counter cache
815:         if options[:counter_cache]
816:           cache_column = options[:counter_cache] == true ?
817:             "#{self.to_s.underscore.pluralize}_count" :
818:             options[:counter_cache]
819:
820:           module_eval(
821:             "after_create '#{reflection.name}.class.increment_counter(\"#{cache_column}\", #{reflection.primary_key_name})" +
822:             " unless #{reflection.name}.nil?'"
823:           )
824:
825:           module_eval(
826:             "before_destroy '#{reflection.name}.class.decrement_counter(\"#{cache_column}\", #{reflection.primary_key_name})" +
827:             " unless #{reflection.name}.nil?'"
828:           )
829:
830:           module_eval(
831:             "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)"
832:           )
833:         end
834:       end
has_and_belongs_to_many(association_id, options = {}, &extension)

Associates two classes via an intermediate join table. Unless the join table is explicitly specified as an option, it is guessed using the lexical order of the class names. So a join between Developer and Project will give the default join table name of developers_projects because "D" outranks "P". Note that this precedence is calculated using the < operator for String. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables paper_boxes and papers to generate a join table name of papers_paper_boxes because of the length of the name paper_boxes, but it in fact generates a join table name of paper_boxes_papers. Be aware of this caveat, and use the custom join_table option if you need to.

Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through has_and_belongs_to_many associations. Records returned from join tables with additional attributes will be marked as ReadOnly (because we can‘t save changes to the additional attributes). It‘s strongly recommended that you upgrade any associations with attributes to a real join model (see introduction).

Adds the following methods for retrieval and query: collection is replaced with the symbol passed as the first argument, so has_and_belongs_to_many :categories would add among others categories.empty?.

  • collection(force_reload = false) - returns an array of all the associated objects. An empty array is returned if none are found.
  • collection<<(object, …) - adds one or more objects to the collection by creating associations in the join table (collection.push and collection.concat are aliases to this method).
  • collection.delete(object, …) - removes one or more objects from the collection by removing their associations from the join table. This does not destroy the objects.
  • collection=objects - replaces the collection‘s content by deleting and adding objects as appropriate.
  • collection_singular_ids - returns an array of the associated objects’ ids
  • collection_singular_ids=ids - replace the collection by the objects identified by the primary keys in ids
  • collection.clear - removes every object from the collection. This does not destroy the objects.
  • collection.empty? - returns true if there are no associated objects.
  • collection.size - returns the number of associated objects.
  • collection.find(id) - finds an associated object responding to the id and that meets the condition that it has to be associated with this object.
  • collection.build(attributes = {}) - returns a new object of the collection type that has been instantiated with attributes and linked to this object through the join table, but has not yet been saved.
  • collection.create(attributes = {}) - returns a new object of the collection type that has been instantiated with attributes, linked to this object through the join table, and that has already been saved (if it passed the validation).

Example: A Developer class declares has_and_belongs_to_many :projects, which will add:

  • Developer#projects
  • Developer#projects<<
  • Developer#projects.delete
  • Developer#projects=
  • Developer#project_ids
  • Developer#project_ids=
  • Developer#projects.clear
  • Developer#projects.empty?
  • Developer#projects.size
  • Developer#projects.find(id)
  • Developer#projects.build (similar to Project.new("project_id" => id))
  • Developer#projects.create (similar to c = Project.new("project_id" => id); c.save; c)

The declaration may include an options hash to specialize the behavior of the association.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can‘t be inferred from the association name. So has_and_belongs_to_many :projects will by default be linked to the Project class, but if the real class name is SuperProject, you‘ll have to specify it with this option.
  • :join_table - specify the name of the join table if the default based on lexical order isn‘t what you want. WARNING: If you‘re overwriting the table name of either class, the table_name method MUST be declared underneath any has_and_belongs_to_many declaration in order to work.
  • :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and _id suffixed. So a Person class that makes a has_and_belongs_to_many association will use person_id as the default foreign_key.
  • :association_foreign_key - specify the association foreign key used for the association. By default this is guessed to be the name of the associated class in lower-case and _id suffixed. So if the associated class is Project, the has_and_belongs_to_many association will use project_id as the default association foreign_key.
  • :conditions - specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1.
  • :order - specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC
  • :uniq - if set to true, duplicate associated objects will be ignored by accessors and query methods
  • :finder_sql - overwrite the default generated SQL statement used to fetch the association with a manual statement
  • :delete_sql - overwrite the default generated SQL statement used to remove links between the associated classes with a manual statement
  • :insert_sql - overwrite the default generated SQL statement used to add links between the associated classes with a manual statement
  • :extend - anonymous module for extending the proxy, see "Association extensions".
  • :include - specify second-order associations that should be eager loaded when the collection is loaded.
  • :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
  • :limit: An integer determining the limit on the number of rows that should be returned.
  • :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
  • :select: By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join but not include the joined columns.

Option examples:

  has_and_belongs_to_many :projects
  has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
  has_and_belongs_to_many :nations, :class_name => "Country"
  has_and_belongs_to_many :categories, :join_table => "prods_cats"
  has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
  'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}'

[ show source ]

     # File activerecord/lib/active_record/associations.rb, line 951
951:       def has_and_belongs_to_many(association_id, options = {}, &extension)
952:         reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
953:
954:         add_multiple_associated_save_callbacks(reflection.name)
955:         collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
956:
957:         # Don't use a before_destroy callback since users' before_destroy
958:         # callbacks will be executed after the association is wiped out.
959:         old_method = "destroy_without_habtm_shim_for_#{reflection.name}"
960:         class_eval "alias_method :\#{old_method}, :destroy_without_callbacks\ndef destroy_without_callbacks\n\#{reflection.name}.clear\n\#{old_method}\nend\n" unless method_defined?(old_method)
961:
962:         add_association_callbacks(reflection.name, options)
963:       end
has_many(association_id, options = {}, &extension)

Adds the following methods for retrieval and query of collections of associated objects: collection is replaced with the symbol passed as the first argument, so has_many :clients would add among others clients.empty?.

  • collection(force_reload = false) - returns an array of all the associated objects. An empty array is returned if none are found.
  • collection<<(object, …) - adds one or more objects to the collection by setting their foreign keys to the collection‘s primary key.
  • collection.delete(object, …) - removes one or more objects from the collection by setting their foreign keys to NULL. This will also destroy the objects if they‘re declared as belongs_to and dependent on this model.
  • collection=objects - replaces the collections content by deleting and adding objects as appropriate.
  • collection_singular_ids - returns an array of the associated objects’ ids
  • collection_singular_ids=ids - replace the collection with the objects identified by the primary keys in ids
  • collection.clear - removes every object from the collection. This destroys the associated objects if they are associated with :dependent => :destroy, deletes them directly from the database if :dependent => :delete_all, otherwise sets their foreign keys to NULL.
  • collection.empty? - returns true if there are no associated objects.
  • collection.size - returns the number of associated objects.
  • collection.find - finds an associated object according to the same rules as Base.find.
  • collection.build(attributes = {}, …) - returns one or more new objects of the collection type that have been instantiated with attributes and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an associated object already exists, not if it‘s nil!
  • collection.create(attributes = {}) - returns a new object of the collection type that has been instantiated with attributes, linked to this object through a foreign key, and that has already been saved (if it passed the validation). *Note:* This only works if an associated object already exists, not if it‘s nil!

Example: A Firm class declares has_many :clients, which will add:

  • Firm#clients (similar to Clients.find :all, :conditions => "firm_id = #{id}")
  • Firm#clients<<
  • Firm#clients.delete
  • Firm#clients=
  • Firm#client_ids
  • Firm#client_ids=
  • Firm#clients.clear
  • Firm#clients.empty? (similar to firm.clients.size == 0)
  • Firm#clients.size (similar to Client.count "firm_id = #{id}")
  • Firm#clients.find (similar to Client.find(id, :conditions => "firm_id = #{id}"))
  • Firm#clients.build (similar to Client.new("firm_id" => id))
  • Firm#clients.create (similar to c = Client.new("firm_id" => id); c.save; c)

The declaration can also include an options hash to specialize the behavior of the association.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can‘t be inferred from the association name. So has_many :products will by default be linked to the Product class, but if the real class name is SpecialProduct, you‘ll have to specify it with this option.
  • :conditions - specify the conditions that the associated objects must meet in order to be included as a WHERE SQL fragment, such as price > 5 AND name LIKE ‘B%’.
  • :order - specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC
  • :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and _id suffixed. So a Person class that makes a has_many association will use person_id as the default foreign_key.
  • :dependent - if set to :destroy all the associated objects are destroyed alongside this object by calling their destroy method. If set to :delete_all all associated objects are deleted without calling their destroy method. If set to :nullify all associated objects’ foreign keys are set to NULL without calling their save callbacks.
  • :finder_sql - specify a complete SQL statement to fetch the association. This is a good way to go for complex associations that depend on multiple tables. Note: When this option is used, find_in_collection is not added.
  • :counter_sql - specify a complete SQL statement to fetch the size of the association. If :finder_sql is specified but not :counter_sql, :counter_sql will be generated by replacing SELECT … FROM with SELECT COUNT(*) FROM.
  • :extend - specify a named module for extending the proxy. See "Association extensions".
  • :include - specify second-order associations that should be eager loaded when the collection is loaded.
  • :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
  • :limit: An integer determining the limit on the number of rows that should be returned.
  • :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
  • :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not include the joined columns.
  • :as: Specifies a polymorphic interface (See belongs_to).
  • :through: Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to or has_many association on the join model.
  • :source: Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, :through => :subscriptions will look for either :subscribers or :subscriber on Subscription, unless a :source is given.
  • :source_type: Specifies type of the source association used by has_many :through queries where the source association is a polymorphic belongs_to.
  • :uniq - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.

Option examples:

  has_many :comments, :order => "posted_on"
  has_many :comments, :include => :author
  has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
  has_many :tracks, :order => "position", :dependent => :destroy
  has_many :comments, :dependent => :nullify
  has_many :tags, :as => :taggable
  has_many :subscribers, :through => :subscriptions, :source => :user
  has_many :subscribers, :class_name => "Person", :finder_sql =>
      'SELECT DISTINCT people.* ' +
      'FROM people p, post_subscriptions ps ' +
      'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
      'ORDER BY p.first_name'

[ show source ]

     # File activerecord/lib/active_record/associations.rb, line 666
666:       def has_many(association_id, options = {}, &extension)
667:         reflection = create_has_many_reflection(association_id, options, &extension)
668:
669:         configure_dependency_for_has_many(reflection)
670:
671:         if options[:through]
672:           collection_reader_method(reflection, HasManyThroughAssociation)
673:           collection_accessor_methods(reflection, HasManyThroughAssociation, false)
674:         else
675:           add_multiple_associated_save_callbacks(reflection.name)
676:           add_association_callbacks(reflection.name, reflection.options)
677:           collection_accessor_methods(reflection, HasManyAssociation)
678:         end
679:       end
has_one(association_id, options = {})

Adds the following methods for retrieval and query of a single associated object: association is replaced with the symbol passed as the first argument, so has_one :manager would add among others manager.nil?.

  • association(force_reload = false) - returns the associated object. nil is returned if none is found.
  • association=(associate) - assigns the associate object, extracts the primary key, sets it as the foreign key, and saves the associate object.
  • association.nil? - returns true if there is no associated object.
  • build_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if an association already exists. It will NOT work if the association is nil.
  • create_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes, linked to this object through a foreign key, and that has already been saved (if it passed the validation).

Example: An Account class declares has_one :beneficiary, which will add:

  • Account#beneficiary (similar to Beneficiary.find(:first, :conditions => "account_id = #{id}"))
  • Account#beneficiary=(beneficiary) (similar to beneficiary.account_id = account.id; beneficiary.save)
  • Account#beneficiary.nil?
  • Account#build_beneficiary (similar to Beneficiary.new("account_id" => id))
  • Account#create_beneficiary (similar to b = Beneficiary.new("account_id" => id); b.save; b)

The declaration can also include an options hash to specialize the behavior of the association.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can‘t be inferred from the association name. So has_one :manager will by default be linked to the Manager class, but if the real class name is Person, you‘ll have to specify it with this option.
  • :conditions - specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as rank = 5.
  • :order - specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC
  • :dependent - if set to :destroy, the associated object is destroyed when this object is. If set to :delete, the associated object is deleted without calling its destroy method. If set to :nullify, the associated object‘s foreign key is set to NULL. Also, association is assigned.
  • :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and _id suffixed. So a Person class that makes a has_one association will use person_id as the default foreign_key.
  • :include - specify second-order associations that should be eager loaded when this object is loaded.
  • :as: Specifies a polymorphic interface (See belongs_to).

Option examples:

  has_one :credit_card, :dependent => :destroy  # destroys the associated credit card
  has_one :credit_card, :dependent => :nullify  # updates the associated records foreign key value to NULL rather than destroying it
  has_one :last_comment, :class_name => "Comment", :order => "posted_on"
  has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
  has_one :attachment, :as => :attachable

[ show source ]

     # File activerecord/lib/active_record/associations.rb, line 726
726:       def has_one(association_id, options = {})
727:         reflection = create_has_one_reflection(association_id, options)
728:
729:         module_eval do
730:           after_save "association = instance_variable_get(\"@\#{reflection.name}\")\nif !association.nil? && (new_record? || association.new_record? || association[\"\#{reflection.primary_key_name}\"] != id)\nassociation[\"\#{reflection.primary_key_name}\"] = id\nassociation.save(true)\nend\n"
731:         end
732:
733:         association_accessor_methods(reflection, HasOneAssociation)
734:         association_constructor_method(:build,  reflection, HasOneAssociation)
735:         association_constructor_method(:create, reflection, HasOneAssociation)
736:
737:         configure_dependency_for_has_one(reflection)
738:       end


Class: ActiveRecord::Associations::ClassMethods::InnerJoinDependency::InnerJoinAssociation

Class
ActiveRecord::Associations::ClassMethods::InnerJoinDependency::InnerJoinAssociation
In: | activerecord/lib/active_record/associations.rb
Parent: | JoinAssociation


Module: ActiveRecord::AttributeMethods::ClassMethods

Module
ActiveRecord::AttributeMethods::ClassMethods
In: activerecord/lib/active_record/attribute_methods.rb

Declare and check for suffixed attribute methods.

Methods
  • attribute_method_suffix
  • cache_attribute?
  • cache_attributes
  • cached_attributes
  • define_attribute_methods
  • define_read_methods
  • generated_methods?
  • instance_method_already_implemented?
  • match_attribute_method?
Public Instance methods
attribute_method_suffix(*suffixes)

Declare a method available for all attributes with the given suffix. Uses method_missing and respond_to? to rewrite the method

  #{attr}#{suffix}(*args, &block)

to

  attribute#{suffix}(#{attr}, *args, &block)

An attribute#{suffix} instance method must exist and accept at least the attr argument.

For example:

  class Person < ActiveRecord::Base
    attribute_method_suffix '_changed?'

    private
      def attribute_changed?(attr)
        ...
      end
  end

  person = Person.find(1)
  person.name_changed?    # => false
  person.name = 'Hubert'
  person.name_changed?    # => true

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 38
38:       def attribute_method_suffix(*suffixes)
39:         attribute_method_suffixes.concat suffixes
40:         rebuild_attribute_method_regexp
41:       end
cache_attribute?(attr_name)

[ show source ]

     # File activerecord/lib/active_record/attribute_methods.rb, line 107
107:       def cache_attribute?(attr_name)
108:         cached_attributes.include?(attr_name)
109:       end
cache_attributes(*attribute_names)

cache_attributes allows you to declare which converted attribute values should be cached. Usually caching only pays off for attributes with expensive conversion methods, like date columns (e.g. created_at, updated_at).

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 97
97:       def cache_attributes(*attribute_names)
98:         attribute_names.each {|attr| cached_attributes << attr.to_s}
99:       end
cached_attributes()

returns the attributes where

[ show source ]

     # File activerecord/lib/active_record/attribute_methods.rb, line 102
102:       def cached_attributes
103:         @cached_attributes ||=
104:           columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set
105:       end
define_attribute_methods()

generates all the attribute related methods for columns in the database accessors, mutators and query methods

This method is also aliased as define_read_methods

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 61
61:       def define_attribute_methods
62:         return if generated_methods?
63:         columns_hash.each do |name, column|
64:           unless instance_method_already_implemented?(name)
65:             if self.serialized_attributes[name]
66:               define_read_method_for_serialized_attribute(name)
67:             else
68:               define_read_method(name.to_sym, name, column)
69:             end
70:           end
71:
72:           unless instance_method_already_implemented?("#{name}=")
73:             define_write_method(name.to_sym)
74:           end
75:
76:           unless instance_method_already_implemented?("#{name}?")
77:             define_question_method(name)
78:           end
79:         end
80:       end
define_read_methods()

Alias for define_attribute_methods

generated_methods?()

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 55
55:       def generated_methods?
56:         !generated_methods.empty?
57:       end
instance_method_already_implemented?(method_name)

Check to see if the method is defined in the model or any of its subclasses that also derive from ActiveRecord. Raise DangerousAttributeError if the method is defined by ActiveRecord though.

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 84
84:       def instance_method_already_implemented?(method_name)
85:         return true if method_name =~ /^id(=$|\?$|$)/
86:         @_defined_class_methods         ||= Set.new(ancestors.first(ancestors.index(ActiveRecord::Base)).collect! { |m| m.public_instance_methods(false) | m.private_instance_methods(false) | m.protected_instance_methods(false) }.flatten)
87:         @@_defined_activerecord_methods ||= Set.new(ActiveRecord::Base.public_instance_methods(false) | ActiveRecord::Base.private_instance_methods(false) | ActiveRecord::Base.protected_instance_methods(false))
88:         raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
89:         @_defined_class_methods.include?(method_name)
90:       end
match_attribute_method?(method_name)

Returns MatchData if method_name is an attribute method.

[ show source ]

    # File activerecord/lib/active_record/attribute_methods.rb, line 44
44:       def match_attribute_method?(method_name)
45:         rebuild_attribute_method_regexp unless defined?(@@attribute_method_regexp) && @@attribute_method_regexp
46:         @@attribute_method_regexp.match(method_name)
47:       end


Module: ActiveRecord::Calculations::ClassMethods

Module
ActiveRecord::Calculations::ClassMethods
In: activerecord/lib/active_record/calculations.rb
Methods
  • average
  • calculate
  • construct_count_options_from_args
  • count
  • maximum
  • minimum
  • sum
Public Instance methods
average(column_name, options = {})

Calculates the average value on a given column. The value is returned as a float. See calculate for examples with options.

  Person.average('age')

[ show source ]

    # File activerecord/lib/active_record/calculations.rb, line 52
52:       def average(column_name, options = {})
53:         calculate(:avg, column_name, options)
54:       end
calculate(operation, column_name, options = {})

This calculates aggregate values in the given column. Methods for count, sum, average, minimum, and maximum have been added as shortcuts. Options such as :conditions, :order, :group, :having, and :joins can be passed to customize the query.

There are two basic forms of output:

  * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float for AVG, and the given column's type for everything else.
  * Grouped values: This returns an ordered hash of the values and groups them by the :group option.  It takes either a column name, or the name
    of a belongs_to association.

      values = Person.maximum(:age, :group => 'last_name')
      puts values["Drake"]
      => 43

      drake  = Family.find_by_last_name('Drake')
      values = Person.maximum(:age, :group => :family) # Person belongs_to :family
      puts values[drake]
      => 43

      values.each do |family, max_age|
      ...
      end

Options:

  • :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
  • :include: Eager loading, see Associations for details. Since calculations don‘t load anything, the purpose of this is to access fields on joined tables in your conditions, order, or group clauses.
  • :joins - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). The records will be returned read-only since they will have attributes that do not correspond to the table‘s columns.
  • :order - An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
  • :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
  • :select - By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not include the joined columns.
  • :distinct - Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) …

Examples:

  Person.calculate(:count, :all) # The same as Person.count
  Person.average(:age) # SELECT AVG(age) FROM people...
  Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for everyone with a last name other than 'Drake'
  Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name) # Selects the minimum age for any family without any minors

[ show source ]

     # File activerecord/lib/active_record/calculations.rb, line 114
114:       def calculate(operation, column_name, options = {})
115:         validate_calculation_options(operation, options)
116:         column_name     = options[:select] if options[:select]
117:         column_name     = '*' if column_name == :all
118:         column          = column_for column_name
119:         catch :invalid_query do
120:           if options[:group]
121:             return execute_grouped_calculation(operation, column_name, column, options)
122:           else
123:             return execute_simple_calculation(operation, column_name, column, options)
124:           end
125:         end
126:         0
127:       end
count(*args)

Count operates using three different approaches.

  • Count all: By not passing any parameters to count, it will return a count of all the rows for the model.
  • Count using column : By passing a column name to count, it will return a count of all the rows for the model with supplied column present
  • Count using options will find the row count matched by the options used.

The third approach, count using options, accepts an option hash as the only parameter. The options are:

  • :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
  • :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table‘s columns. Pass :readonly => false to override.
  • :include: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer to already defined associations. When using named associations, count returns the number of DISTINCT items for the model you‘re counting. See eager loading under Associations.
  • :order: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
  • :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
  • :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not include the joined columns.
  • :distinct: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) …

Examples for counting all:

  Person.count         # returns the total count of all people

Examples for counting by column:

  Person.count(:age)  # returns the total count of all people whose age is present in database

Examples for count with options:

  Person.count(:conditions => "age > 26")
  Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN.
  Person.count(:conditions => "age > 26 AND job.salary > 60000", :joins => "LEFT JOIN jobs on jobs.person_id = person.id") # finds the number of rows matching the conditions and joins.
  Person.count('id', :conditions => "age > 26") # Performs a COUNT(id)
  Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*')

Note: Person.count(:all) will not work because it will use :all as the condition. Use Person.count instead.

[ show source ]

    # File activerecord/lib/active_record/calculations.rb, line 45
45:       def count(*args)
46:         calculate(:count, *construct_count_options_from_args(*args))
47:       end
maximum(column_name, options = {})

Calculates the maximum value on a given column. The value is returned with the same data type of the column. See calculate for examples with options.

  Person.maximum('age')

[ show source ]

    # File activerecord/lib/active_record/calculations.rb, line 66
66:       def maximum(column_name, options = {})
67:         calculate(:max, column_name, options)
68:       end
minimum(column_name, options = {})

Calculates the minimum value on a given column. The value is returned with the same data type of the column. See calculate for examples with options.

  Person.minimum('age')

[ show source ]

    # File activerecord/lib/active_record/calculations.rb, line 59
59:       def minimum(column_name, options = {})
60:         calculate(:min, column_name, options)
61:       end
sum(column_name, options = {})

Calculates the sum of values on a given column. The value is returned with the same data type of the column. See calculate for examples with options.

  Person.sum('age')

[ show source ]

    # File activerecord/lib/active_record/calculations.rb, line 73
73:       def sum(column_name, options = {})
74:         calculate(:sum, column_name, options)
75:       end
Protected Instance methods
construct_count_options_from_args(*args)

[ show source ]

     # File activerecord/lib/active_record/calculations.rb, line 130
130:         def construct_count_options_from_args(*args)
131:           options     = {}
132:           column_name = :all
133:
134:           # We need to handle
135:           #   count()
136:           #   count(:column_name=:all)
137:           #   count(options={})
138:           #   count(column_name=:all, options={})
139:           case args.size
140:           when 1
141:             args[0].is_a?(Hash) ? options = args[0] : column_name = args[0]
142:           when 2
143:             column_name, options = args
144:           else
145:             raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}"
146:           end if args.size > 0
147:
148:           [column_name, options]
149:         end


Module: ActiveRecord::Callbacks

Module
ActiveRecord::Callbacks
In: activerecord/lib/active_record/callbacks.rb

Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic before or after an alteration of the object state. This can be used to make sure that associated and dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes before they‘re validated (by overwriting before_validation). As an example of the callbacks initiated, consider the Base#save call:

  • (-) save
  • (-) valid
  • (1) before_validation
  • (2) before_validation_on_create
  • (-) validate
  • (-) validate_on_create
  • (3) after_validation
  • (4) after_validation_on_create
  • (5) before_save
  • (6) before_create
  • (-) create
  • (7) after_create
  • (8) after_save

That‘s a total of eight callbacks, which gives you immense power to react and prepare for each state in the Active Record lifecycle.

Examples:

  class CreditCard < ActiveRecord::Base
    # Strip everything but digits, so the user can specify "555 234 34" or
    # "5552-3434" or both will mean "55523434"
    def before_validation_on_create
      self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
    end
  end

  class Subscription < ActiveRecord::Base
    before_create :record_signup

    private
      def record_signup
        self.signed_up_on = Date.today
      end
  end

  class Firm < ActiveRecord::Base
    # Destroys the associated clients and people when the firm is destroyed
    before_destroy { |record| Person.destroy_all "firm_id = #{record.id}"   }
    before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
  end

Inheritable callback queues

Besides the overwriteable callback methods, it‘s also possible to register callbacks through the use of the callback macros. Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance hierarchy. Example:

  class Topic < ActiveRecord::Base
    before_destroy :destroy_author
  end

  class Reply < Topic
    before_destroy :destroy_readers
  end

Now, when Topic#destroy is run only destroy_author is called. When Reply#destroy is run, both destroy_author and destroy_readers are called. Contrast this to the situation where we‘ve implemented the save behavior through overwriteable methods:

  class Topic < ActiveRecord::Base
    def before_destroy() destroy_author end
  end

  class Reply < Topic
    def before_destroy() destroy_readers end
  end

In that case, Reply#destroy would only run destroy_readers and not destroy_author. So, use the callback macros when you want to ensure that a certain callback is called for the entire hierarchy, and use the regular overwriteable methods when you want to leave it up to each descendent to decide whether they want to call super and trigger the inherited callbacks.

*IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won‘t be inherited.

Types of callbacks

There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects, inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for creating mix-ins), and inline eval methods are deprecated.

The method reference callbacks work by specifying a protected or private method available in the object, like this:

  class Topic < ActiveRecord::Base
    before_destroy :delete_parents

    private
      def delete_parents
        self.class.delete_all "parent_id = #{id}"
      end
  end

The callback objects have methods named after the callback called with the record as the only parameter, such as:

  class BankAccount < ActiveRecord::Base
    before_save      EncryptionWrapper.new("credit_card_number")
    after_save       EncryptionWrapper.new("credit_card_number")
    after_initialize EncryptionWrapper.new("credit_card_number")
  end

  class EncryptionWrapper
    def initialize(attribute)
      @attribute = attribute
    end

    def before_save(record)
      record.credit_card_number = encrypt(record.credit_card_number)
    end

    def after_save(record)
      record.credit_card_number = decrypt(record.credit_card_number)
    end

    alias_method :after_find, :after_save

    private
      def encrypt(value)
        # Secrecy is committed
      end

      def decrypt(value)
        # Secrecy is unveiled
      end
  end

So you specify the object you want messaged on a given callback. When that callback is triggered, the object has a method by the name of the callback messaged.

The callback macros usually accept a symbol for the method they‘re supposed to run, but you can also pass a "method string", which will then be evaluated within the binding of the callback. Example:

  class Topic < ActiveRecord::Base
    before_destroy 'self.class.delete_all "parent_id = #{id}"'
  end

Notice that single quotes (’) are used so the #{id} part isn‘t evaluated until the callback is triggered. Also note that these inline callbacks can be stacked just like the regular ones:

  class Topic < ActiveRecord::Base
    before_destroy 'self.class.delete_all "parent_id = #{id}"',
                   'puts "Evaluated after parents are destroyed"'
  end

The after_find and after_initialize exceptions

Because after_find and after_initialize are called for each object found and instantiated by a finder, such as Base.find(:all), we‘ve had to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, after_find and after_initialize will only be run if an explicit implementation is defined (def after_find). In that case, all of the callback types will be called.

before_validation* returning statements

If the returning value of a before_validation callback can be evaluated to false, the process will be aborted and Base#save will return false. If Base#save! is called it will raise a RecordNotSaved exception. Nothing will be appended to the errors object.

Canceling callbacks

If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.

Methods
  • after_create
  • after_destroy
  • after_save
  • after_update
  • after_validation
  • after_validation_on_create
  • after_validation_on_update
  • before_create
  • before_destroy
  • before_save
  • before_update
  • before_validation
  • before_validation_on_create
  • before_validation_on_update
Constants
CALLBACKS = %w( after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation after_validation before_validation_on_create after_validation_on_create before_validation_on_update after_validation_on_update before_destroy after_destroy )
Public Instance methods
after_create()

Is called after Base.save on new objects that haven‘t been saved yet (no record exists).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 224
224:     def after_create() end
after_destroy()

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

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 293
293:     def after_destroy()  end
after_save()

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

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 211
211:     def after_save()  end
after_update()

Is called after Base.save on existing objects that have a record.

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 237
237:     def after_update() end
after_validation()

Is called after Validations.validate (which is part of the Base.save call).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 251
251:     def after_validation() end
after_validation_on_create()

Is called after Validations.validate (which is part of the Base.save call) on new objects that haven‘t been saved yet (no record exists).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 259
259:     def after_validation_on_create()  end
after_validation_on_update()

Is called after Validations.validate (which is part of the Base.save call) on existing objects that have a record.

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 267
267:     def after_validation_on_update()  end
before_create()

Is called before Base.save on new objects that haven‘t been saved yet (no record exists).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 221
221:     def before_create() end
before_destroy()

Is called before Base.destroy.

Note: If you need to destroy or nullify associated records first, use the :dependent option on your associations.

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 286
286:     def before_destroy() end
before_save()

Is called before Base.save (regardless of whether it‘s a create or update save).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 204
204:     def before_save() end
before_update()

Is called before Base.save on existing objects that have a record.

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 234
234:     def before_update() end
before_validation()

Is called before Validations.validate (which is part of the Base.save call).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 248
248:     def before_validation() end
before_validation_on_create()

Is called before Validations.validate (which is part of the Base.save call) on new objects that haven‘t been saved yet (no record exists).

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 255
255:     def before_validation_on_create() end
before_validation_on_update()

Is called before Validations.validate (which is part of the Base.save call) on existing objects that have a record.

[ show source ]

     # File activerecord/lib/active_record/callbacks.rb, line 263
263:     def before_validation_on_update() end


Class: ActiveRecord::ConfigurationError

Class
ActiveRecord::ConfigurationError
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when association is being configured improperly or user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.


Class: ActiveRecord::ConnectionAdapters::AbstractAdapter

Class
ActiveRecord::ConnectionAdapters::AbstractAdapter
In: | activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
Parent: | Object

All the concrete database adapters follow the interface laid down in this class. You can use this interface directly by borrowing the database connection from the Base with Base.connection.

Most of the methods in the adapter are useful during migrations. Most notably, SchemaStatements#create_table, SchemaStatements#drop_table, SchemaStatements#add_index, SchemaStatements#remove_index, SchemaStatements#add_column, SchemaStatements#change_column and SchemaStatements#remove_column are very useful.

Methods
  • active?
  • adapter_name
  • disable_referential_integrity
  • disconnect!
  • format_log_entry
  • log
  • log_info
  • prefetch_primary_key?
  • quote_table_name
  • raw_connection
  • reconnect!
  • requires_reloading?
  • supports_count_distinct?
  • supports_migrations?
  • verify!
Included Modules
  • Quoting
  • DatabaseStatements
  • SchemaStatements
  • QueryCache
Public Instance methods
active?()

Is this connection active and ready to perform queries?

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 83
83:       def active?
84:         @active != false
85:       end
adapter_name()

Returns the human-readable name of the adapter. Use mixed case - one can always use downcase if needed.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 37
37:       def adapter_name
38:         'Abstract'
39:       end
disable_referential_integrity() {|| ...}

Override to turn off referential integrity while executing +&block+

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 76
76:       def disable_referential_integrity(&block)
77:         yield
78:       end
disconnect!()

Close this connection

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 93
93:       def disconnect!
94:         @active = false
95:       end
log_info(sql, name, runtime)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 120
120:       def log_info(sql, name, runtime)
121:         if @logger && @logger.debug?
122:           name = "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})"
123:           @logger.debug format_log_entry(name, sql.squeeze(' '))
124:         end
125:       end
prefetch_primary_key?(table_name = nil)

Should primary key values be selected from their corresponding sequence before the insert statement? If true, next_sequence_value is called before each insert to set the record‘s primary key. This is false for all adapters but Firebird.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 57
57:       def prefetch_primary_key?(table_name = nil)
58:         false
59:       end
quote_table_name(name)

Override to return the quoted table name if the database needs it

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 69
69:       def quote_table_name(name)
70:         name
71:       end
raw_connection()

Provides access to the underlying database connection. Useful for when you need to call a proprietary method such as postgresql‘s lo_* methods

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 116
116:       def raw_connection
117:         @connection
118:       end
reconnect!()

Close this connection and open a new one in its place.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 88
88:       def reconnect!
89:         @active = true
90:       end
requires_reloading?()

Returns true if its safe to reload the connection between requests for development mode. This is not the case for Ruby/MySQL and it‘s not necessary for any adapters except SQLite.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 99
 99:       def requires_reloading?
100:         false
101:       end
supports_count_distinct?()

Does this adapter support using DISTINCT within COUNT? This is true for all adapters except sqlite.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 49
49:       def supports_count_distinct?
50:         true
51:       end
supports_migrations?()

Does this adapter support migrations? Backend specific, as the abstract adapter always returns false.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 43
43:       def supports_migrations?
44:         false
45:       end
verify!(timeout)

Lazily verify this connection, calling +active?+ only if it hasn‘t been called for timeout seconds.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 105
105:       def verify!(timeout)
106:         now = Time.now.to_i
107:         if (now - @last_verification) > timeout
108:           reconnect! unless active?
109:           @last_verification = now
110:         end
111:       end
Protected Instance methods
format_log_entry(message, dump = nil)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 153
153:         def format_log_entry(message, dump = nil)
154:           if ActiveRecord::Base.colorize_logging
155:             if @@row_even
156:               @@row_even = false
157:               message_color, dump_color = "4;36;1", "0;1"
158:             else
159:               @@row_even = true
160:               message_color, dump_color = "4;35;1", "0"
161:             end
162:
163:             log_entry = "  \e[#{message_color}m#{message}\e[0m   "
164:             log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
165:             log_entry
166:           else
167:             "%s  %s" % [message, dump]
168:           end
169:         end
log(sql, name) {|| ...}

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 128
128:         def log(sql, name)
129:           if block_given?
130:             if @logger and @logger.debug?
131:               result = nil
132:               seconds = Benchmark.realtime { result = yield }
133:               @runtime += seconds
134:               log_info(sql, name, seconds)
135:               result
136:             else
137:               yield
138:             end
139:           else
140:             log_info(sql, name, 0)
141:             nil
142:           end
143:         rescue Exception => e
144:           # Log message and raise exception.
145:           # Set last_verification to 0, so that connection gets verified
146:           # upon reentering the request loop
147:           @last_verification = 0
148:           message = "#{e.class.name}: #{e.message}: #{sql}"
149:           log_info(message, name, 0)
150:           raise ActiveRecord::StatementInvalid, message
151:         end


Class: ActiveRecord::ConnectionAdapters::Column

Class
ActiveRecord::ConnectionAdapters::Column
In: | activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
Parent: | Object

An abstract definition of a column in a table.

Methods
  • binary_to_string
  • extract_default
  • fallback_string_to_date
  • fallback_string_to_time
  • fast_string_to_date
  • fast_string_to_time
  • human_name
  • klass
  • microseconds
  • new
  • new_date
  • new_time
  • number?
  • string_to_binary
  • string_to_date
  • string_to_dummy_time
  • string_to_time
  • text?
  • type_cast
  • type_cast_code
  • value_to_boolean
  • value_to_decimal
Classes and Modules
Module ActiveRecord::ConnectionAdapters::Column::Format
Attributes
[R] | default
[R] | limit
[R] | name
[R] | null
[R] | precision
[RW] | primary
[R] | scale
[R] | sql_type
[R] | type
Public Class methods
binary_to_string(value)

Used to convert from BLOBs to Strings

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 111
111:         def binary_to_string(value)
112:           value
113:         end
new(name, default, sql_type = nil, null = true)

Instantiates a new column in the table.

name is the column‘s name, as in supplier_id int(11). default is the type-casted default value, such as sales_stage varchar(20) default ‘new‘. sql_type is only used to extract the column‘s length, if necessary. For example, company_name varchar(60). null determines if this column allows NULL values.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 23
23:       def initialize(name, default, sql_type = nil, null = true)
24:         @name, @sql_type, @null = name, sql_type, null
25:         @limit, @precision, @scale  = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
26:         @type = simplified_type(sql_type)
27:         @default = extract_default(default)
28:
29:         @primary = nil
30:       end
string_to_binary(value)

Used to convert from Strings to BLOBs

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 106
106:         def string_to_binary(value)
107:           value
108:         end
string_to_date(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 115
115:         def string_to_date(string)
116:           return string unless string.is_a?(String)
117:           return nil if string.empty?
118:
119:           fast_string_to_date(string) || fallback_string_to_date(string)
120:         end
string_to_dummy_time(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 129
129:         def string_to_dummy_time(string)
130:           return string unless string.is_a?(String)
131:           return nil if string.empty?
132:
133:           string_to_time "2000-01-01 #{string}"
134:         end
string_to_time(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 122
122:         def string_to_time(string)
123:           return string unless string.is_a?(String)
124:           return nil if string.empty?
125:
126:           fast_string_to_time(string) || fallback_string_to_time(string)
127:         end
value_to_boolean(value)

convert something to a boolean

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 137
137:         def value_to_boolean(value)
138:           if value == true || value == false
139:             value
140:           else
141:             %w(true t 1).include?(value.to_s.downcase)
142:           end
143:         end
value_to_decimal(value)

convert something to a BigDecimal

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 146
146:         def value_to_decimal(value)
147:           if value.is_a?(BigDecimal)
148:             value
149:           elsif value.respond_to?(:to_d)
150:             value.to_d
151:           else
152:             value.to_s.to_d
153:           end
154:         end
Protected Class methods
fallback_string_to_date(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 194
194:           def fallback_string_to_date(string)
195:             new_date *ParseDate.parsedate(string)[0..2]
196:           end
fallback_string_to_time(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 198
198:           def fallback_string_to_time(string)
199:             time_hash = Date._parse(string)
200:             time_hash[:sec_fraction] = microseconds(time_hash)
201:
202:             new_time *time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction)
203:           end
fast_string_to_date(string)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 180
180:           def fast_string_to_date(string)
181:             if string =~ Format::ISO_DATE
182:               new_date $1.to_i, $2.to_i, $3.to_i
183:             end
184:           end
fast_string_to_time(string)

Doesn‘t handle time zones.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 187
187:           def fast_string_to_time(string)
188:             if string =~ Format::ISO_DATETIME
189:               microsec = ($7.to_f * 1_000_000).to_i
190:               new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
191:             end
192:           end
microseconds(time)

‘0.123456’ -> 123456 ‘1.123456’ -> 123456

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 159
159:           def microseconds(time)
160:             ((time[:sec_fraction].to_f % 1) * 1_000_000).to_i
161:           end
new_date(year, mon, mday)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 163
163:           def new_date(year, mon, mday)
164:             if year && year != 0
165:               Date.new(year, mon, mday) rescue nil
166:             end
167:           end
new_time(year, mon, mday, hour, min, sec, microsec)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 169
169:           def new_time(year, mon, mday, hour, min, sec, microsec)
170:             # Treat 0000-00-00 00:00:00 as nil.
171:             return nil if year.nil? || year == 0
172:
173:             Time.send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec)
174:           # Over/underflow to DateTime
175:           rescue ArgumentError, TypeError
176:             zone_offset = Base.default_timezone == :local ? DateTime.local_offset : 0
177:             DateTime.civil(year, mon, mday, hour, min, sec, zone_offset) rescue nil
178:           end
Public Instance methods
extract_default(default)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 100
100:       def extract_default(default)
101:         type_cast(default)
102:       end
human_name()

Returns the human name of the column name.

Examples
 Column.new('sales_stage', ...).human_name #=> 'Sales stage'

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 96
96:       def human_name
97:         Base.human_attribute_name(@name)
98:       end
klass()

Returns the Ruby class that corresponds to the abstract data type.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 41
41:       def klass
42:         case type
43:           when :integer       then Fixnum
44:           when :float         then Float
45:           when :decimal       then BigDecimal
46:           when :datetime      then Time
47:           when :date          then Date
48:           when :timestamp     then Time
49:           when :time          then Time
50:           when :text, :string then String
51:           when :binary        then String
52:           when :boolean       then Object
53:         end
54:       end
number?()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 36
36:       def number?
37:         [:float, :integer, :decimal].include? type
38:       end
text?()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 32
32:       def text?
33:         [:string, :text].include? type
34:       end
type_cast(value)

Casts value (which is a String) to an appropriate instance.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 57
57:       def type_cast(value)
58:         return nil if value.nil?
59:         case type
60:           when :string    then value
61:           when :text      then value
62:           when :integer   then value.to_i rescue value ? 1 : 0
63:           when :float     then value.to_f
64:           when :decimal   then self.class.value_to_decimal(value)
65:           when :datetime  then self.class.string_to_time(value)
66:           when :timestamp then self.class.string_to_time(value)
67:           when :time      then self.class.string_to_dummy_time(value)
68:           when :date      then self.class.string_to_date(value)
69:           when :binary    then self.class.binary_to_string(value)
70:           when :boolean   then self.class.value_to_boolean(value)
71:           else value
72:         end
73:       end
type_cast_code(var_name)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 75
75:       def type_cast_code(var_name)
76:         case type
77:           when :string    then nil
78:           when :text      then nil
79:           when :integer   then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
80:           when :float     then "#{var_name}.to_f"
81:           when :decimal   then "#{self.class.name}.value_to_decimal(#{var_name})"
82:           when :datetime  then "#{self.class.name}.string_to_time(#{var_name})"
83:           when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
84:           when :time      then "#{self.class.name}.string_to_dummy_time(#{var_name})"
85:           when :date      then "#{self.class.name}.string_to_date(#{var_name})"
86:           when :binary    then "#{self.class.name}.binary_to_string(#{var_name})"
87:           when :boolean   then "#{self.class.name}.value_to_boolean(#{var_name})"
88:           else nil
89:         end
90:       end


Module: ActiveRecord::ConnectionAdapters::Column::Format

Module
ActiveRecord::ConnectionAdapters::Column::Format
In: activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
Constants
ISO_DATE | = | /\A(\d{4})-(\d\d)-(\d\d)\z/
ISO_DATETIME | = | /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/


Module: ActiveRecord::ConnectionAdapters::DatabaseStatements

Module
ActiveRecord::ConnectionAdapters::DatabaseStatements
In: activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
Methods
  • add_limit!
  • add_limit_offset!
  • add_lock!
  • begin_db_transaction
  • commit_db_transaction
  • default_sequence_name
  • delete
  • delete_sql
  • empty_insert_statement
  • execute
  • insert
  • insert_fixture
  • insert_sql
  • reset_sequence!
  • rollback_db_transaction
  • select
  • select_all
  • select_one
  • select_rows
  • select_value
  • select_values
  • transaction
  • update
  • update_sql
Public Instance methods
add_limit!(sql, options)

Alias for add_limit_offset!.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 97
97:       def add_limit!(sql, options)
98:         add_limit_offset!(sql, options) if options
99:       end
add_limit_offset!(sql, options)

Appends LIMIT and OFFSET options to an SQL statement. This method modifies the sql parameter.

Examples
 add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})

generates

 SELECT * FROM suppliers LIMIT 10 OFFSET 50

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 107
107:       def add_limit_offset!(sql, options)
108:         if limit = options[:limit]
109:           sql << " LIMIT #{limit}"
110:           if offset = options[:offset]
111:             sql << " OFFSET #{offset}"
112:           end
113:         end
114:       end
add_lock!(sql, options)

Appends a locking clause to an SQL statement. This method modifies the sql parameter.

  # SELECT * FROM suppliers FOR UPDATE
  add_lock! 'SELECT * FROM suppliers', :lock => true
  add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 121
121:       def add_lock!(sql, options)
122:         case lock = options[:lock]
123:           when true;   sql << ' FOR UPDATE'
124:           when String; sql << " #{lock}"
125:         end
126:       end
begin_db_transaction()

Begins the transaction (and turns off auto-committing).

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 87
87:       def begin_db_transaction()    end
commit_db_transaction()

Commits the transaction (and turns on auto-committing).

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 90
90:       def commit_db_transaction()   end
default_sequence_name(table, column)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 128
128:       def default_sequence_name(table, column)
129:         nil
130:       end
delete(sql, name = nil)

Executes the delete statement and returns the number of rows affected.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 53
53:       def delete(sql, name = nil)
54:         delete_sql(sql, name)
55:       end
empty_insert_statement(table_name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 143
143:       def empty_insert_statement(table_name)
144:         "INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
145:       end
execute(sql, name = nil)

Executes the SQL statement in the context of this connection.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 38
38:       def execute(sql, name = nil)
39:         raise NotImplementedError, "execute is an abstract method"
40:       end
insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)

Returns the last auto-generated ID from the affected table.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 43
43:       def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
44:         insert_sql(sql, name, pk, id_value, sequence_name)
45:       end
insert_fixture(fixture, table_name)

Inserts the given fixture into the table. Overridden in adapters that require something beyond a simple insert (eg. Oracle).

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 139
139:       def insert_fixture(fixture, table_name)
140:         execute "INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
141:       end
reset_sequence!(table, column, sequence = nil)

Set the sequence to the max value of the table‘s column.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 133
133:       def reset_sequence!(table, column, sequence = nil)
134:         # Do nothing by default.  Implement for PostgreSQL, Oracle, ...
135:       end
rollback_db_transaction()

Rolls back the transaction (and turns on auto-committing). Must be done if the transaction block raises an exception or returns false.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 94
94:       def rollback_db_transaction() end
select_all(sql, name = nil)

Returns an array of record hashes with the column names as keys and column values as values.

[ show source ]

   # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 6
6:       def select_all(sql, name = nil)
7:         select(sql, name)
8:       end
select_one(sql, name = nil)

Returns a record hash with the column names as keys and column values as values.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 12
12:       def select_one(sql, name = nil)
13:         result = select_all(sql, name)
14:         result.first if result
15:       end
select_rows(sql, name = nil)

Returns an array of arrays containing the field values. Order is the same as that returned by columns.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 33
33:       def select_rows(sql, name = nil)
34:         raise NotImplementedError, "select_rows is an abstract method"
35:       end
select_value(sql, name = nil)

Returns a single value from a record

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 18
18:       def select_value(sql, name = nil)
19:         if result = select_one(sql, name)
20:           result.values.first
21:         end
22:       end
select_values(sql, name = nil)

Returns an array of the values of the first column in a select:

  select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 26
26:       def select_values(sql, name = nil)
27:         result = select_rows(sql, name)
28:         result.map { |v| v[0] }
29:       end
transaction(start_db_transaction = true) {|| ...}

Wrap a block in a transaction. Returns result of block.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 58
58:       def transaction(start_db_transaction = true)
59:         transaction_open = false
60:         begin
61:           if block_given?
62:             if start_db_transaction
63:               begin_db_transaction
64:               transaction_open = true
65:             end
66:             yield
67:           end
68:         rescue Exception => database_transaction_rollback
69:           if transaction_open
70:             transaction_open = false
71:             rollback_db_transaction
72:           end
73:           raise unless database_transaction_rollback.is_a? ActiveRecord::Rollback
74:         end
75:       ensure
76:         if transaction_open
77:           begin
78:             commit_db_transaction
79:           rescue Exception => database_transaction_rollback
80:             rollback_db_transaction
81:             raise
82:           end
83:         end
84:       end
update(sql, name = nil)

Executes the update statement and returns the number of rows affected.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 48
48:       def update(sql, name = nil)
49:         update_sql(sql, name)
50:       end
Protected Instance methods
delete_sql(sql, name = nil)

Executes the delete statement and returns the number of rows affected.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 166
166:         def delete_sql(sql, name = nil)
167:           update_sql(sql, name)
168:         end
insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)

Returns the last auto-generated ID from the affected table.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 155
155:         def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
156:           execute(sql, name)
157:           id_value
158:         end
select(sql, name = nil)

Returns an array of record hashes with the column names as keys and column values as values.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 150
150:         def select(sql, name = nil)
151:           raise NotImplementedError, "select is an abstract method"
152:         end
update_sql(sql, name = nil)

Executes the update statement and returns the number of rows affected.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 161
161:         def update_sql(sql, name = nil)
162:           execute(sql, name)
163:         end


Module: ActiveRecord::ConnectionAdapters::QueryCache

Module
ActiveRecord::ConnectionAdapters::QueryCache
In: activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
Methods
  • cache
  • clear_query_cache
  • columns_with_query_cache
  • dirties_query_cache
  • included
  • select_all_with_query_cache
  • uncached
Public Class methods
dirties_query_cache(base, *method_names)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 15
15:         def dirties_query_cache(base, *method_names)
16:           method_names.each do |method_name|
17:             base.class_eval "def \#{method_name}_with_query_dirty(*args)\nclear_query_cache if @query_cache_enabled\n\#{method_name}_without_query_dirty(*args)\nend\n\nalias_method_chain :\#{method_name}, :query_dirty\n", __FILE__, __LINE__
18:           end
19:         end
included(base)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 5
 5:         def included(base)
 6:           base.class_eval do
 7:             attr_accessor :query_cache_enabled
 8:             alias_method_chain :columns, :query_cache
 9:             alias_method_chain :select_all, :query_cache
10:           end
11:
12:           dirties_query_cache base, :insert, :update, :delete
13:         end
Public Instance methods
cache() {|| ...}

Enable the query cache within the block.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 31
31:       def cache
32:         old, @query_cache_enabled = @query_cache_enabled, true
33:         @query_cache ||= {}
34:         yield
35:       ensure
36:         clear_query_cache
37:         @query_cache_enabled = old
38:       end
clear_query_cache()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 48
48:       def clear_query_cache
49:         @query_cache.clear if @query_cache
50:       end
columns_with_query_cache(*args)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 60
60:       def columns_with_query_cache(*args)
61:         if @query_cache_enabled
62:           @query_cache["SHOW FIELDS FROM #{args.first}"] ||= columns_without_query_cache(*args)
63:         else
64:           columns_without_query_cache(*args)
65:         end
66:       end
select_all_with_query_cache(*args)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 52
52:       def select_all_with_query_cache(*args)
53:         if @query_cache_enabled
54:           cache_sql(args.first) { select_all_without_query_cache(*args) }
55:         else
56:           select_all_without_query_cache(*args)
57:         end
58:       end
uncached() {|| ...}

Disable the query cache within the block.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb, line 41
41:       def uncached
42:         old, @query_cache_enabled = @query_cache_enabled, false
43:         yield
44:       ensure
45:         @query_cache_enabled = old
46:       end


Module: ActiveRecord::ConnectionAdapters::Quoting

Module
ActiveRecord::ConnectionAdapters::Quoting
In: activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
Methods
  • quote
  • quote_column_name
  • quote_string
  • quote_table_name
  • quoted_date
  • quoted_false
  • quoted_string_prefix
  • quoted_true
Public Instance methods
quote(value, column = nil)

Quotes the column value to help prevent SQL injection attacks.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 6
 6:       def quote(value, column = nil)
 7:         # records are quoted as their primary key
 8:         return value.quoted_id if value.respond_to?(:quoted_id)
 9:
10:         case value
11:           when String, ActiveSupport::Multibyte::Chars
12:             value = value.to_s
13:             if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
14:               "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
15:             elsif column && [:integer, :float].include?(column.type)
16:               value = column.type == :integer ? value.to_i : value.to_f
17:               value.to_s
18:             else
19:               "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
20:             end
21:           when NilClass                 then "NULL"
22:           when TrueClass                then (column && column.type == :integer ? '1' : quoted_true)
23:           when FalseClass               then (column && column.type == :integer ? '0' : quoted_false)
24:           when Float, Fixnum, Bignum    then value.to_s
25:           # BigDecimals need to be output in a non-normalized form and quoted.
26:           when BigDecimal               then value.to_s('F')
27:           else
28:             if value.acts_like?(:date) || value.acts_like?(:time)
29:               "'#{quoted_date(value)}'"
30:             else
31:               "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
32:             end
33:         end
34:       end
quote_column_name(column_name)

Quotes the column name. Defaults to no quoting.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 43
43:       def quote_column_name(column_name)
44:         column_name
45:       end
quote_string(s)

Quotes a string, escaping any ’ (single quote) and \ (backslash) characters.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 38
38:       def quote_string(s)
39:         s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
40:       end
quote_table_name(table_name)

Quotes the table name. Defaults to column name quoting.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 48
48:       def quote_table_name(table_name)
49:         quote_column_name(table_name)
50:       end
quoted_date(value)

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 60
60:       def quoted_date(value)
61:         value.to_s(:db)
62:       end
quoted_false()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 56
56:       def quoted_false
57:         "'f'"
58:       end
quoted_string_prefix()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 64
64:       def quoted_string_prefix
65:         ''
66:       end
quoted_true()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/quoting.rb, line 52
52:       def quoted_true
53:         "'t'"
54:       end


Class: ActiveRecord::ConnectionAdapters::SQLiteAdapter

Class
ActiveRecord::ConnectionAdapters::SQLiteAdapter
In: | activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
Parent: | AbstractAdapter

The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby drivers (available both as gems and from rubyforge.org/projects/sqlite-ruby/).

Options:

  • :database — Path to the database file.
Methods
  • catch_schema_changes
  • default_primary_key_type
  • disconnect!
  • empty_insert_statement
  • rename_table
  • requires_reloading?
  • select_rows
  • sqlite_version
  • table_structure
Public Instance methods
disconnect!()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 87
87:       def disconnect!
88:         super
89:         @connection.close rescue nil
90:       end
empty_insert_statement(table_name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 251
251:       def empty_insert_statement(table_name)
252:         "INSERT INTO #{table_name} VALUES(NULL)"
253:       end
rename_table(name, new_name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 213
213:       def rename_table(name, new_name)
214:         execute "ALTER TABLE #{name} RENAME TO #{new_name}"
215:       end
requires_reloading?()

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 83
83:       def requires_reloading?
84:         true
85:       end
select_rows(sql, name = nil)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 149
149:       def select_rows(sql, name = nil)
150:         execute(sql, name).map do |row|
151:           (0...(row.size / 2)).map { |i| row[i] }
152:         end
153:       end
Protected Instance methods
catch_schema_changes() {|| ...}

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 345
345:         def catch_schema_changes
346:           return yield
347:         rescue ActiveRecord::StatementInvalid => exception
348:           if exception.message =~ /database schema has changed/
349:             reconnect!
350:             retry
351:           else
352:             raise
353:           end
354:         end
default_primary_key_type()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 360
360:         def default_primary_key_type
361:           if supports_autoincrement?
362:             'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'.freeze
363:           else
364:             'INTEGER PRIMARY KEY NOT NULL'.freeze
365:           end
366:         end
sqlite_version()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 356
356:         def sqlite_version
357:           @sqlite_version ||= select_value('select sqlite_version(*)')
358:         end
table_structure(table_name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 268
268:         def table_structure(table_name)
269:           returning structure = execute("PRAGMA table_info(#{table_name})") do
270:             raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
271:           end
272:         end


Module: ActiveRecord::ConnectionAdapters::SchemaStatements

Module
ActiveRecord::ConnectionAdapters::SchemaStatements
In: activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
Methods
  • add_column
  • add_index
  • add_order_by_for_association_limiting!
  • change_column
  • change_column_default
  • columns
  • create_table
  • distinct
  • drop_table
  • initialize_schema_information
  • native_database_types
  • options_include_default?
  • remove_column
  • remove_index
  • rename_column
  • rename_table
  • structure_dump
  • table_alias_for
  • table_alias_length
Public Instance methods
add_column(table_name, column_name, type, options = {})

Adds a new column to the named table. See TableDefinition#column for details of the options you can use.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 121
121:       def add_column(table_name, column_name, type, options = {})
122:         add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
123:         add_column_options!(add_column_sql, options)
124:         execute(add_column_sql)
125:       end
add_index(table_name, column_name, options = {})

Adds a new index to the table. column_name can be a single Symbol, or an Array of Symbols.

The index will be named after the table and the first column name, unless you pass +:name+ as an option.

When creating an index on multiple columns, the first column is used as a name for the index. For example, when you specify an index on two columns [+:first+, +:last+], the DBMS creates an index for both columns as well as an index for the first column +:first+. Using just the first name for this index makes sense, because you will never have to create a singular index with this name.

Examples
Creating a simple index
 add_index(:suppliers, :name)

generates

 CREATE INDEX suppliers_name_index ON suppliers(name)
Creating a unique index
 add_index(:accounts, [:branch_id, :party_id], :unique => true)

generates

 CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
Creating a named index
 add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')

generates

 CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 186
186:       def add_index(table_name, column_name, options = {})
187:         column_names = Array(column_name)
188:         index_name   = index_name(table_name, :column => column_names)
189:
190:         if Hash === options # legacy support, since this param was a string
191:           index_type = options[:unique] ? "UNIQUE" : ""
192:           index_name = options[:name] || index_name
193:         else
194:           index_type = options
195:         end
196:         quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
197:         execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
198:       end
add_order_by_for_association_limiting!(sql, options)

ORDER BY clause for the passed order option. PostgreSQL overrides this due to its stricter standards compliance.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 296
296:       def add_order_by_for_association_limiting!(sql, options)
297:         sql << " ORDER BY #{options[:order]}"
298:       end
change_column(table_name, column_name, type, options = {})

Changes the column‘s definition according to the new options. See TableDefinition#column for details of the options you can use.

Examples
 change_column(:suppliers, :name, :string, :limit => 80)
 change_column(:accounts, :description, :text)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 139
139:       def change_column(table_name, column_name, type, options = {})
140:         raise NotImplementedError, "change_column is not implemented"
141:       end
change_column_default(table_name, column_name, default)

Sets a new default value for a column. If you want to set the default value to NULL, you are out of luck. You need to DatabaseStatements#execute the appropriate SQL statement yourself.

Examples
 change_column_default(:suppliers, :qualification, 'new')
 change_column_default(:accounts, :authorized, 1)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 149
149:       def change_column_default(table_name, column_name, default)
150:         raise NotImplementedError, "change_column_default is not implemented"
151:       end
columns(table_name, name = nil)

Returns an array of Column objects for the table specified by table_name. See the concrete implementation for details on the expected parameter values.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 28
28:       def columns(table_name, name = nil) end
create_table(table_name, options = {}) {|table_definition| ...}

Creates a new table There are two ways to work with create_table. You can use the block form or the regular form, like this:

Block form

 # create_table() yields a TableDefinition instance
 create_table(:suppliers) do |t|
   t.column :name, :string, :limit => 60
   # Other fields here
 end

Regular form

 create_table(:suppliers)
 add_column(:suppliers, :name, :string, {:limit => 60})

The options hash can include the following keys:

:id
Whether to automatically add a primary key column. Defaults to true. Join tables for has_and_belongs_to_many should set :id => false.
:primary_key
The name of the primary key, if one is to be added automatically. Defaults to id.
:options
Any extra options you want appended to the table definition.
:temporary
Make a temporary table.
:force
Set to true to drop the table before creating it. Defaults to false.
Examples
Add a backend specific option to the generated SQL (MySQL)
 create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')

generates:

 CREATE TABLE suppliers (
   id int(11) DEFAULT NULL auto_increment PRIMARY KEY
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
Rename the primary key column
 create_table(:objects, :primary_key => 'guid') do |t|
   t.column :name, :string, :limit => 80
 end

generates:

 CREATE TABLE objects (
   guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
   name varchar(80)
 )
Do not add a primary key column
 create_table(:categories_suppliers, :id => false) do |t|
   t.column :category_id, :integer
   t.column :supplier_id, :integer
 end

generates:

 CREATE TABLE categories_suppliers (
   category_id int,
   supplier_id int
 )

See also TableDefinition#column for details on how to create columns.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 90
 90:       def create_table(table_name, options = {})
 91:         table_definition = TableDefinition.new(self)
 92:         table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
 93:
 94:         yield table_definition
 95:
 96:         if options[:force]
 97:           drop_table(table_name, options) rescue nil
 98:         end
 99:
100:         create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
101:         create_sql << "#{quote_table_name(table_name)} ("
102:         create_sql << table_definition.to_sql
103:         create_sql << ") #{options[:options]}"
104:         execute create_sql
105:       end
distinct(columns, order_by)

SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.

  distinct("posts.id", "posts.created_at desc")

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 290
290:       def distinct(columns, order_by)
291:         "DISTINCT #{columns}"
292:       end
drop_table(table_name, options = {})

Drops a table from the database.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 115
115:       def drop_table(table_name, options = {})
116:         execute "DROP TABLE #{quote_table_name(table_name)}"
117:       end
initialize_schema_information()

Should not be called normally, but this operation is non-destructive. The migrations module handles this automatically.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 235
235:       def initialize_schema_information
236:         begin
237:           execute "CREATE TABLE #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version #{type_to_sql(:integer)})"
238:           execute "INSERT INTO #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version) VALUES(0)"
239:         rescue ActiveRecord::StatementInvalid
240:           # Schema has been initialized
241:         end
242:       end
native_database_types()

Returns a Hash of mappings from the abstract data types to the native database types. See TableDefinition#column for details on the recognized abstract data types.

[ show source ]

   # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 7
7:       def native_database_types
8:         {}
9:       end
remove_column(table_name, column_name)

Removes the column from the table definition.

Examples
 remove_column(:suppliers, :qualification)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 130
130:       def remove_column(table_name, column_name)
131:         execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
132:       end
remove_index(table_name, options = {})

Remove the given index from the table.

Remove the suppliers_name_index in the suppliers table.

  remove_index :suppliers, :name

Remove the index named accounts_branch_id_index in the accounts table.

  remove_index :accounts, :column => :branch_id

Remove the index named accounts_branch_id_party_id_index in the accounts table.

  remove_index :accounts, :column => [:branch_id, :party_id]

Remove the index named by_branch_party in the accounts table.

  remove_index :accounts, :name => :by_branch_party

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 210
210:       def remove_index(table_name, options = {})
211:         execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
212:       end
rename_column(table_name, column_name, new_column_name)

Renames a column.

Example
 rename_column(:suppliers, :description, :name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 156
156:       def rename_column(table_name, column_name, new_column_name)
157:         raise NotImplementedError, "rename_column is not implemented"
158:       end
rename_table(table_name, new_name)

Renames a table.

Example
 rename_table('octopuses', 'octopi')

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 110
110:       def rename_table(table_name, new_name)
111:         raise NotImplementedError, "rename_table is not implemented"
112:       end
structure_dump()

Returns a string of CREATE TABLE SQL statement(s) for recreating the entire structure of the database.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 230
230:       def structure_dump
231:       end
table_alias_for(table_name)

Truncates a table alias according to the limits of the current adapter.

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 17
17:       def table_alias_for(table_name)
18:         table_name[0..table_alias_length-1].gsub(/\./, '_')
19:       end
table_alias_length()

This is the maximum length a table alias can be

[ show source ]

    # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 12
12:       def table_alias_length
13:         255
14:       end
Protected Instance methods
options_include_default?(options)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 301
301:         def options_include_default?(options)
302:           options.include?(:default) && !(options[:null] == false && options[:default].nil?)
303:         end


Class: ActiveRecord::ConnectionAdapters::TableDefinition

Class
ActiveRecord::ConnectionAdapters::TableDefinition
In: | activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
Parent: | Object

Represents a SQL table in an abstract way. Columns are stored as a ColumnDefinition in the columns attribute.

Methods
  • []
  • belongs_to
  • column
  • new
  • primary_key
  • references
  • timestamps
  • to_sql
Attributes
[RW] columns
Public Class methods
new(base)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 278
278:       def initialize(base)
279:         @columns = []
280:         @base = base
281:       end
Public Instance methods
[](name)

Returns a ColumnDefinition for the column with name name.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 290
290:       def [](name)
291:         @columns.find {|column| column.name.to_s == name.to_s}
292:       end
belongs_to(*args)

Alias for references

column(name, type, options = {})

Instantiates a new column for the table. The type parameter is normally one of the migrations native types, which is one of the following: :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean.

You may use a type not in this list as long as it is supported by your database (for example, "polygon" in MySQL), but this will not be database agnostic and should usually be avoided.

Available options are (none of these exists by default):

  • :limit - Requests a maximum column length (:string, :text, :binary or :integer columns only)
  • :default - The column‘s default value. Use nil for NULL.
  • :null - Allows or disallows NULL values in the column. This option could have been named :null_allowed.
  • :precision - Specifies the precision for a :decimal column.
  • :scale - Specifies the scale for a :decimal column.

Please be aware of different RDBMS implementations behavior with :decimal columns:

  • The SQL standard says the default scale should be 0, :scale <= :precision, and makes no comments about the requirements of :precision.
  • MySQL: :precision [1..63], :scale [0..30]. Default is (10,0).
  • PostgreSQL: :precision [1..infinity], :scale [0..infinity]. No default.
  • SQLite2: Any :precision and :scale may be used. Internal storage as strings. No default.
  • SQLite3: No restrictions on :precision and :scale, but the maximum supported :precision is 16. No default.
  • Oracle: :precision [1..38], :scale [-84..127]. Default is (38,0).
  • DB2: :precision [1..63], :scale [0..62]. Default unknown.
  • Firebird: :precision [1..18], :scale [0..18]. Default (9,0). Internal types NUMERIC and DECIMAL have different storage rules, decimal being better.
  • FrontBase?: :precision [1..38], :scale [0..38]. Default (38,0). WARNING Max :precision/:scale for NUMERIC is 19, and DECIMAL is 38.
  • SqlServer?: :precision [1..38], :scale [0..38]. Default (38,0).
  • Sybase: :precision [1..38], :scale [0..38]. Default (38,0).
  • OpenBase?: Documentation unclear. Claims storage in double.

This method returns self.

Examples

 # Assuming td is an instance of TableDefinition
 td.column(:granted, :boolean)
   #=> granted BOOLEAN

 td.column(:picture, :binary, :limit => 2.megabytes)
   #=> picture BLOB(2097152)

 td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
   #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL

 def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
   #=> bill_gates_money DECIMAL(15,2)

 def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
   #=> sensor_reading DECIMAL(30,20)

 # While <tt>:scale</tt> defaults to zero on most databases, it
 # probably wouldn't hurt to include it.
 def.column(:huge_integer, :decimal, :precision => 30)
   #=> huge_integer DECIMAL(30)

Short-hand examples

Instead of calling column directly, you can also work with the short-hand definitions for the default types. They use the type as the method name instead of as a parameter and allow for multiple columns to be defined in a single statement.

What can be written like this with the regular calls to column:

  create_table "products", :force => true do |t|
    t.column "shop_id",    :integer
    t.column "creator_id", :integer
    t.column "name",       :string,   :default => "Untitled"
    t.column "value",      :string,   :default => "Untitled"
    t.column "created_at", :datetime
    t.column "updated_at", :datetime
  end

Can also be written as follows using the short-hand:

  create_table :products do |t|
    t.integer :shop_id, :creator_id
    t.string  :name, :value, :default => "Untitled"
    t.timestamps
  end

There‘s a short-hand method for each of the type values declared at the top. And then there‘s TableDefinition#timestamps that‘ll add created_at and updated_at as datetimes.

TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be used when creating the _type column. So what can be written like this:

  create_table :taggings do |t|
    t.integer :tag_id, :tagger_id, :taggable_id
    t.string  :tagger_type
    t.string  :taggable_type, :default => 'Photo'
  end

Can also be written as follows using references:

  create_table :taggings do |t|
    t.references :tag
    t.references :tagger, :polymorphic => true
    t.references :taggable, :polymorphic => { :default => 'Photo' }
  end

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 418
418:       def column(name, type, options = {})
419:         column = self[name] || ColumnDefinition.new(@base, name, type)
420:         column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
421:         column.precision = options[:precision]
422:         column.scale = options[:scale]
423:         column.default = options[:default]
424:         column.null = options[:null]
425:         @columns << column unless @columns.include? column
426:         self
427:       end
primary_key(name)

Appends a primary key definition to the table definition. Can be called multiple times, but this is probably not a good idea.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 285
285:       def primary_key(name)
286:         column(name, :primary_key)
287:       end
references(*args)
This method is also aliased as belongs_to

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 448
448:       def references(*args)
449:         options = args.extract_options!
450:         polymorphic = options.delete(:polymorphic)
451:         args.each do |col|
452:           column("#{col}_id", :integer, options)
453:           unless polymorphic.nil?
454:             column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : {})
455:           end
456:         end
457:       end
timestamps()

Appends :datetime columns :created_at and :updated_at to the table.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 443
443:       def timestamps
444:         column(:created_at, :datetime)
445:         column(:updated_at, :datetime)
446:       end
to_sql()

Returns a String whose contents are the column definitions concatenated together. This string can then be prepended and appended to to generate the final SQL to create the table.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 463
463:       def to_sql
464:         @columns * ', '
465:       end


Class: ActiveRecord::ConnectionNotEstablished

Class
ActiveRecord::ConnectionNotEstablished
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when connection to the database could not been established (for example when connection= is given a nil object).


Class: ActiveRecord::DangerousAttributeError

Class
ActiveRecord::DangerousAttributeError
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods).


Class: ActiveRecord::Errors

Class
ActiveRecord::Errors
In: | activerecord/lib/active_record/validations.rb
Parent: | Object

Active Record validation is reported to and from this object, which is used by Base#save to determine whether the object is in a valid state to be saved. See usage example in Validations.

Methods
  • []
  • add
  • add_on_blank
  • add_on_empty
  • add_to_base
  • clear
  • count
  • each
  • each_full
  • empty?
  • full_messages
  • invalid?
  • length
  • on
  • on_base
  • size
  • to_xml
Included Modules
  • Enumerable
Public Instance methods
[](attribute)

Alias for on

add(attribute, msg = @@default_error_messages[:invalid])

Adds an error message (msg) to the attribute, which will be returned on a call to on(attribute) for the same attribute and ensure that this error object returns false when asked if empty?. More than one error can be added to the same attribute in which case an array will be returned on a call to on(attribute). If no msg is supplied, "invalid" is assumed.

[ show source ]

    # File activerecord/lib/active_record/validations.rb, line 64
64:     def add(attribute, msg = @@default_error_messages[:invalid])
65:       @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
66:       @errors[attribute.to_s] << msg
67:     end
add_on_blank(attributes, msg = @@default_error_messages[:blank])

Will add an error message to each of the attributes in attributes that is blank (using Object#blank?).

[ show source ]

    # File activerecord/lib/active_record/validations.rb, line 79
79:     def add_on_blank(attributes, msg = @@default_error_messages[:blank])
80:       for attr in [attributes].flatten
81:         value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
82:         add(attr, msg) if value.blank?
83:       end
84:     end
add_on_empty(attributes, msg = @@default_error_messages[:empty])

Will add an error message to each of the attributes in attributes that is empty.

[ show source ]

    # File activerecord/lib/active_record/validations.rb, line 70
70:     def add_on_empty(attributes, msg = @@default_error_messages[:empty])
71:       for attr in [attributes].flatten
72:         value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
73:         is_empty = value.respond_to?("empty?") ? value.empty? : false
74:         add(attr, msg) unless !value.nil? && !is_empty
75:       end
76:     end
add_to_base(msg)

Adds an error to the base object instead of any particular attribute. This is used to report errors that don‘t tie to any specific attribute, but rather to the object as a whole. These error messages don‘t get prepended with any field name when iterating with each_full, so they should be complete sentences.

[ show source ]

    # File activerecord/lib/active_record/validations.rb, line 56
56:     def add_to_base(msg)
57:       add(:base, msg)
58:     end
clear()

Removes all errors that have been added.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 192
192:     def clear
193:       @errors = {}
194:     end
count()

Alias for size

each() {|attr, msg| ...}

Yields each attribute and associated message per error added.

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } # =>
    name - is too short (minimum is 5 characters)
    name - can't be blank
    address - can't be blank

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 138
138:     def each
139:       @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
140:     end
each_full() {|msg| ...}

Yields each full error message added. So Person.errors.add("first_name", "can‘t be empty") will be returned through iteration as "First name can‘t be empty".

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.each_full{|msg| puts msg } # =>
    Name is too short (minimum is 5 characters)
    Name can't be blank
    Address can't be blank

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 155
155:     def each_full
156:       full_messages.each { |msg| yield msg }
157:     end
empty?()

Returns true if no errors have been added.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 187
187:     def empty?
188:       @errors.empty?
189:     end
full_messages()

Returns all the full error messages in an array.

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.full_messages # =>
    ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"]

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 169
169:     def full_messages
170:       full_messages = []
171:
172:       @errors.each_key do |attr|
173:         @errors[attr].each do |msg|
174:           next if msg.nil?
175:
176:           if attr == "base"
177:             full_messages << msg
178:           else
179:             full_messages << @base.class.human_attribute_name(attr) + " " + msg
180:           end
181:         end
182:       end
183:       full_messages
184:     end
invalid?(attribute)

Returns true if the specified attribute has errors associated with it.

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.invalid?(:name)      # => true
  company.errors.invalid?(:address)   # => false

[ show source ]

    # File activerecord/lib/active_record/validations.rb, line 96
96:     def invalid?(attribute)
97:       !@errors[attribute.to_s].nil?
98:     end
length()

Alias for size

on(attribute)

Returns nil, if no errors are associated with the specified attribute. Returns the error message, if one error is associated with the specified attribute. Returns an array of error messages, if more than one error is associated with the specified attribute.

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.on(:name)      # => ["is too short (minimum is 5 characters)", "can't be blank"]
  company.errors.on(:email)     # => "can't be blank"
  company.errors.on(:address)   # => nil
This method is also aliased as []

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 113
113:     def on(attribute)
114:       errors = @errors[attribute.to_s]
115:       return nil if errors.nil?
116:       errors.size == 1 ? errors.first : errors
117:     end
on_base()

Returns errors assigned to the base object through add_to_base according to the normal rules of on(attribute).

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 122
122:     def on_base
123:       on(:base)
124:     end
size()

Returns the total number of errors added. Two errors added to the same attribute will be counted as such.

This method is also aliased as count length

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 197
197:     def size
198:       @errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
199:     end
to_xml(options={})

Return an XML representation of this error object.

  class Company < ActiveRecord::Base
    validates_presence_of :name, :address, :email
    validates_length_of :name, :in => 5..30
  end

  company = Company.create(:address => '123 First St.')
  company.errors.to_xml # =>
    <?xml version="1.0" encoding="UTF-8"?>
    <errors>
      <error>Name is too short (minimum is 5 characters)</error>
      <error>Name can't be blank</error>
      <error>Address can't be blank</error>
    </errors>

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 219
219:     def to_xml(options={})
220:       options[:root] ||= "errors"
221:       options[:indent] ||= 2
222:       options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
223:
224:       options[:builder].instruct! unless options.delete(:skip_instruct)
225:       options[:builder].errors do |e|
226:         full_messages.each { |msg| e.error(msg) }
227:       end
228:     end


Module: ActiveRecord::Locking

Module
ActiveRecord::Locking
In: activerecord/lib/active_record/locking/optimistic.rb activerecord/lib/active_record/locking/pessimistic.rb
Classes and Modules
Module ActiveRecord::Locking::Optimistic
Module ActiveRecord::Locking::Pessimistic


Module: ActiveRecord::Locking::Optimistic

Module
ActiveRecord::Locking::Optimistic
In: activerecord/lib/active_record/locking/optimistic.rb

What is Optimistic Locking

Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of conflicts with the data. It does this by checking whether another process has made changes to a record since it was opened, an ActiveRecord::StaleObjectError is thrown if that has occurred and the update is ignored.

Check out ActiveRecord::Locking::Pessimistic for an alternative.

Usage

Active Records support optimistic locking if the field lock_version is present. Each update to the record increments the lock_version column and the locking facilities ensure that records instantiated twice will let the last one saved raise a StaleObjectError if the first was also updated. Example:

  p1 = Person.find(1)
  p2 = Person.find(1)

  p1.first_name = "Michael"
  p1.save

  p2.first_name = "should fail"
  p2.save # Raises a ActiveRecord::StaleObjectError

You‘re then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.

You must ensure that your database schema defaults the lock_version column to 0.

This behavior can be turned off by setting ActiveRecord::Base.lock_optimistically = false. To override the name of the lock_version column, invoke the set_locking_column method. This method uses the same syntax as set_table_name

Classes and Modules
Module ActiveRecord::Locking::Optimistic::ClassMethods


Module: ActiveRecord::Locking::Optimistic::ClassMethods

Module
ActiveRecord::Locking::Optimistic::ClassMethods
In: activerecord/lib/active_record/locking/optimistic.rb
Methods
  • extended
  • locking_column
  • locking_enabled?
  • quoted_locking_column
  • reset_locking_column
  • set_locking_column
  • update_counters_with_lock
Constants
DEFAULT_LOCKING_COLUMN = 'lock_version'
Public Class methods
extended(base)

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 101
101:         def self.extended(base)
102:           class <<base
103:             alias_method_chain :update_counters, :lock
104:           end
105:         end
Public Instance methods
locking_column()

The version column used for optimistic locking. Defaults to lock_version.

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 122
122:         def locking_column
123:           reset_locking_column
124:         end
locking_enabled?()

Is optimistic locking enabled for this table? Returns true if the lock_optimistically flag is set to true (which it is, by default) and the table includes the locking_column column (defaults to lock_version).

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 111
111:         def locking_enabled?
112:           lock_optimistically && columns_hash[locking_column]
113:         end
quoted_locking_column()

Quote the column name used for optimistic locking.

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 127
127:         def quoted_locking_column
128:           connection.quote_column_name(locking_column)
129:         end
reset_locking_column()

Reset the column used for optimistic locking back to the lock_version default.

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 132
132:         def reset_locking_column
133:           set_locking_column DEFAULT_LOCKING_COLUMN
134:         end
set_locking_column(value = nil, &block)

Set the column to use for optimistic locking. Defaults to lock_version.

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 116
116:         def set_locking_column(value = nil, &block)
117:           define_attr_method :locking_column, value, &block
118:           value
119:         end
update_counters_with_lock(id, counters)

make sure the lock version column gets updated when counters are updated.

[ show source ]

     # File activerecord/lib/active_record/locking/optimistic.rb, line 138
138:         def update_counters_with_lock(id, counters)
139:           counters = counters.merge(locking_column => 1) if locking_enabled?
140:           update_counters_without_lock(id, counters)
141:         end


Module: ActiveRecord::Locking::Pessimistic

Module
ActiveRecord::Locking::Pessimistic
In: activerecord/lib/active_record/locking/pessimistic.rb

Locking::Pessimistic provides support for row-level locking using SELECT … FOR UPDATE and other lock types.

Pass :lock => true to ActiveRecord::Base.find to obtain an exclusive lock on the selected rows:

  # select * from accounts where id=1 for update
  Account.find(1, :lock => true)

Pass :lock => ‘some locking clause’ to give a database-specific locking clause of your own such as ‘LOCK IN SHARE MODE’ or ‘FOR UPDATE NOWAIT’.

Example:

  Account.transaction do
    # select * from accounts where name = 'shugo' limit 1 for update
    shugo = Account.find(:first, :conditions => "name = 'shugo'", :lock => true)
    yuko = Account.find(:first, :conditions => "name = 'yuko'", :lock => true)
    shugo.balance -= 100
    shugo.save!
    yuko.balance += 100
    yuko.save!
  end

You can also use ActiveRecord::Base#lock! method to lock one record by id. This may be better if you don‘t need to lock every row. Example:

  Account.transaction do
    # select * from accounts where ...
    accounts = Account.find(:all, :conditions => ...)
    account1 = accounts.detect { |account| ... }
    account2 = accounts.detect { |account| ... }
    # select * from accounts where id=? for update
    account1.lock!
    account2.lock!
    account1.balance -= 100
    account1.save!
    account2.balance += 100
    account2.save!
  end

Database-specific information on row locking:

  MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
  PostgreSQL: http://www.postgresql.org/docs/8.1/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
Methods
  • lock!
Public Instance methods
lock!(lock = true)

Obtain a row lock on this record. Reloads the record to obtain the requested lock. Pass an SQL locking clause to append the end of the SELECT statement or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns the locked record.

[ show source ]

    # File activerecord/lib/active_record/locking/pessimistic.rb, line 71
71:       def lock!(lock = true)
72:         reload(:lock => lock) unless new_record?
73:         self
74:       end


Class: ActiveRecord::Migration

Class
ActiveRecord::Migration
In: | activerecord/lib/active_record/migration.rb
Parent: | Object

Migrations can manage the evolution of a schema used by several physical databases. It‘s a solution to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to push that change to other developers and to the production server. With migrations, you can describe the transformations in self-contained classes that can be checked into version control systems and executed against another database that might be one, two, or five versions behind.

Example of a simple migration:

  class AddSsl < ActiveRecord::Migration
    def self.up
      add_column :accounts, :ssl_enabled, :boolean, :default => 1
    end

    def self.down
      remove_column :accounts, :ssl_enabled
    end
  end

This migration will add a boolean flag to the accounts table and remove it if you‘re backing out of the migration. It shows how all migrations have two class methods up and down that describes the transformations required to implement or remove the migration. These methods can consist of both the migration specific methods like add_column and remove_column, but may also contain regular Ruby code for generating data needed for the transformations.

Example of a more complex migration that also needs to initialize data:

  class AddSystemSettings < ActiveRecord::Migration
    def self.up
      create_table :system_settings do |t|
        t.string  :name
        t.string  :label
        t.text  :value
        t.string  :type
        t.integer  :position
      end

      SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
    end

    def self.down
      drop_table :system_settings
    end
  end

This migration first adds the system_settings table, then creates the very first row in it using the Active Record model that relies on the table. It also uses the more advanced create_table syntax where you can specify a complete table schema in one block call.

Available transformations

  • create_table(name, options) Creates a table called name and makes the table object available to a block that can then add columns to it, following the same format as add_column. See example above. The options hash is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create table definition.
  • drop_table(name): Drops the table called name.
  • rename_table(old_name, new_name): Renames the table called old_name to new_name.
  • add_column(table_name, column_name, type, options): Adds a new column to the table called table_name named column_name specified to be one of the following types: :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean. A default value can be specified by passing an options hash like { :default => 11 }. Other options include :limit and :null (e.g. { :limit => 50, :null => false }) — see ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
  • rename_column(table_name, column_name, new_column_name): Renames a column but keeps the type and content.
  • change_column(table_name, column_name, type, options): Changes the column to a different type using the same parameters as add_column.
  • remove_column(table_name, column_name): Removes the column named column_name from the table called table_name.
  • add_index(table_name, column_names, options): Adds a new index with the name of the column. Other options include :name and :unique (e.g. { :name => "users_name_index", :unique => true }).
  • remove_index(table_name, index_name): Removes the index specified by index_name.

Irreversible transformations

Some transformations are destructive in a manner that cannot be reversed. Migrations of that kind should raise an ActiveRecord::IrreversibleMigration exception in their down method.

Running migrations from within Rails

The Rails package has several tools to help create and apply migrations.

To generate a new migration, use script/generate migration MyNewMigration where MyNewMigration is the name of your migration. The generator will create a file nnn_my_new_migration.rb in the db/migrate/ directory where nnn is the next largest migration number. You may then edit the self.up and self.down methods of MyNewMigration.

To run migrations against the currently configured database, use rake db:migrate. This will update the database by running all of the pending migrations, creating the schema_info table if missing.

To roll the database back to a previous migration version, use rake db:migrate VERSION=X where X is the version to which you wish to downgrade. If any of the migrations throw an ActiveRecord::IrreversibleMigration exception, that step will fail and you‘ll have some manual work to do.

Database support

Migrations are currently supported in MySQL, PostgreSQL, SQLite, SQL Server, Sybase, and Oracle (all supported databases except DB2).

More examples

Not all migrations change the schema. Some just fix the data:

  class RemoveEmptyTags < ActiveRecord::Migration
    def self.up
      Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
    end

    def self.down
      # not much we can do to restore deleted data
      raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
    end
  end

Others remove columns when they migrate up instead of down:

  class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
    def self.up
      remove_column :items, :incomplete_items_count
      remove_column :items, :completed_items_count
    end

    def self.down
      add_column :items, :incomplete_items_count
      add_column :items, :completed_items_count
    end
  end

And sometimes you need to do something in SQL not abstracted directly by migrations:

  class MakeJoinUnique < ActiveRecord::Migration
    def self.up
      execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
    end

    def self.down
      execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
    end
  end

Using a model after changing its table

Sometimes you‘ll want to add a column in a migration and populate it immediately after. In that case, you‘ll need to make a call to Base#reset_column_information in order to ensure that the model has the latest column data from after the new column was added. Example:

  class AddPeopleSalary < ActiveRecord::Migration
    def self.up
      add_column :people, :salary, :integer
      Person.reset_column_information
      Person.find(:all).each do |p|
        p.update_attribute :salary, SalaryCalculator.compute(p)
      end
    end
  end

Controlling verbosity

By default, migrations will describe the actions they are taking, writing them to the console as they happen, along with benchmarks describing how long each step took.

You can quiet them down by setting ActiveRecord::Migration.verbose = false.

You can also insert your own messages and benchmarks by using the say_with_time method:

  def self.up
    ...
    say_with_time "Updating salaries..." do
      Person.find(:all).each do |p|
        p.update_attribute :salary, SalaryCalculator.compute(p)
      end
    end
    ...
  end

The phrase "Updating salaries…" would then be printed, along with the benchmark for the block when the block completes.

Methods
  • announce
  • method_missing
  • migrate
  • say
  • say_with_time
  • suppress_messages
  • write
Public Class methods
announce(message)

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 252
252:       def announce(message)
253:         text = "#{@version} #{name}: #{message}"
254:         length = [0, 75 - text.length].max
255:         write "== %s %s" % [text, "=" * length]
256:       end
method_missing(method, *arguments, &block)

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 278
278:       def method_missing(method, *arguments, &block)
279:         arg_list = arguments.map(&:inspect) * ', '
280:
281:         say_with_time "#{method}(#{arg_list})" do
282:           unless arguments.empty? || method == :execute
283:             arguments[0] = Migrator.proper_table_name(arguments.first)
284:           end
285:           ActiveRecord::Base.connection.send(method, *arguments, &block)
286:         end
287:       end
migrate(direction)

Execute this migration in the named direction

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 210
210:       def migrate(direction)
211:         return unless respond_to?(direction)
212:
213:         case direction
214:           when :up   then announce "migrating"
215:           when :down then announce "reverting"
216:         end
217:
218:         result = nil
219:         time = Benchmark.measure { result = send("#{direction}_without_benchmarks") }
220:
221:         case direction
222:           when :up   then announce "migrated (%.4fs)" % time.real; write
223:           when :down then announce "reverted (%.4fs)" % time.real; write
224:         end
225:
226:         result
227:       end
say(message, subitem=false)

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 258
258:       def say(message, subitem=false)
259:         write "#{subitem ? "   ->" : "--"} #{message}"
260:       end
say_with_time(message) {|| ...}

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 262
262:       def say_with_time(message)
263:         say(message)
264:         result = nil
265:         time = Benchmark.measure { result = yield }
266:         say "%.4fs" % time.real, :subitem
267:         say("#{result} rows", :subitem) if result.is_a?(Integer)
268:         result
269:       end
suppress_messages() {|| ...}

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 271
271:       def suppress_messages
272:         save, self.verbose = verbose, false
273:         yield
274:       ensure
275:         self.verbose = save
276:       end
write(text="")

[ show source ]

     # File activerecord/lib/active_record/migration.rb, line 248
248:       def write(text="")
249:         puts(text) if verbose
250:       end


Class: ActiveRecord::MissingAttributeError

Class
ActiveRecord::MissingAttributeError
In: | activerecord/lib/active_record/base.rb
Parent: | NoMethodError

Raised when you‘ve tried to access a column which wasn‘t loaded by your finder. Typically this is because :select has been specified


Class: ActiveRecord::Observer

Class
ActiveRecord::Observer
In: | activerecord/lib/active_record/observer.rb
Parent: | Object

Observer classes respond to lifecycle callbacks to implement trigger-like behavior outside the original class. This is a great way to reduce the clutter that normally comes when the model class is burdened with functionality that doesn‘t pertain to the core responsibility of the class. Example:

  class CommentObserver < ActiveRecord::Observer
    def after_save(comment)
      Notifications.deliver_comment("admin@do.com", "New comment was posted", comment)
    end
  end

This Observer sends an email when a Comment#save is finished.

  class ContactObserver < ActiveRecord::Observer
    def after_create(contact)
      contact.logger.info('New contact added!')
    end

    def after_destroy(contact)
      contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
    end
  end

This Observer uses logger to log when specific callbacks are triggered.

Observing a class that can‘t be inferred

Observers will by default be mapped to the class with which they share a name. So CommentObserver will be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer differently than the class you‘re interested in observing, you can use the Observer.observe class method which takes either the concrete class (Product) or a symbol for that class (:product):

  class AuditObserver < ActiveRecord::Observer
    observe :account

    def after_update(account)
      AuditTrail.new(account, "UPDATED")
    end
  end

If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:

  class AuditObserver < ActiveRecord::Observer
    observe :account, :balance

    def after_update(record)
      AuditTrail.new(record, "UPDATED")
    end
  end

The AuditObserver will now act on both updates to Account and Balance by treating them both as records.

Available callback methods

The observer can implement callback methods for each of the methods described in the Callbacks module.

Storing Observers in Rails

If you‘re using Active Record within Rails, observer classes are usually stored in app/models with the naming convention of app/models/audit_observer.rb.

Configuration

In order to activate an observer, list it in the config.active_record.observers configuration setting in your config/environment.rb file.

  config.active_record.observers = :comment_observer, :signup_observer

Observers will not be invoked unless you define these in your application configuration.

Methods
  • add_observer!
  • new
  • observe
  • observed_class
  • observed_classes
  • observed_subclasses
Included Modules
  • Singleton
Public Class methods
new()

Start observing the declared classes and their subclasses.

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 151
151:     def initialize
152:       Set.new(observed_classes + observed_subclasses).each { |klass| add_observer! klass }
153:     end
observe(*models)

Attaches the observer to the supplied model classes.

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 133
133:       def observe(*models)
134:         models.flatten!
135:         models.collect! { |model| model.is_a?(Symbol) ? model.to_s.camelize.constantize : model }
136:         define_method(:observed_classes) { Set.new(models) }
137:       end
observed_class()

The class observed by default is inferred from the observer‘s class name:

  assert_equal [Person], PersonObserver.observed_class

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 141
141:       def observed_class
142:         if observed_class_name = name.scan(/(.*)Observer/)[0]
143:           observed_class_name[0].constantize
144:         else
145:           nil
146:         end
147:       end
Protected Instance methods
add_observer!(klass)

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 176
176:       def add_observer!(klass)
177:         klass.add_observer(self)
178:         klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
179:       end
observed_classes()

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 168
168:       def observed_classes
169:         Set.new([self.class.observed_class].compact.flatten)
170:       end
observed_subclasses()

[ show source ]

     # File activerecord/lib/active_record/observer.rb, line 172
172:       def observed_subclasses
173:         observed_classes.collect(&:subclasses).flatten
174:       end


Module: ActiveRecord::Observing::ClassMethods

Module
ActiveRecord::Observing::ClassMethods
In: activerecord/lib/active_record/observer.rb
Methods
  • inherited
  • instantiate_observers
  • observers
  • observers=
Public Instance methods
instantiate_observers()

Instantiate the global ActiveRecord observers

[ show source ]

    # File activerecord/lib/active_record/observer.rb, line 34
34:       def instantiate_observers
35:         return if @observers.blank?
36:         @observers.each do |observer|
37:           if observer.respond_to?(:to_sym) # Symbol or String
38:             observer.to_s.camelize.constantize.instance
39:           elsif observer.respond_to?(:instance)
40:             observer.instance
41:           else
42:             raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
43:           end
44:         end
45:       end
observers()

Gets the current observers.

[ show source ]

    # File activerecord/lib/active_record/observer.rb, line 29
29:       def observers
30:         @observers ||= []
31:       end
observers=(*observers)

Activates the observers assigned. Examples:

  # Calls PersonObserver.instance
  ActiveRecord::Base.observers = :person_observer

  # Calls Cacher.instance and GarbageCollector.instance
  ActiveRecord::Base.observers = :cacher, :garbage_collector

  # Same as above, just using explicit class references
  ActiveRecord::Base.observers = Cacher, GarbageCollector

Note: Setting this does not instantiate the observers yet. instantiate_observers is called during startup, and before each development request.

[ show source ]

    # File activerecord/lib/active_record/observer.rb, line 24
24:       def observers=(*observers)
25:         @observers = observers.flatten
26:       end
Protected Instance methods
inherited(subclass)

Notify observers when the observed class is subclassed.

[ show source ]

    # File activerecord/lib/active_record/observer.rb, line 49
49:         def inherited(subclass)
50:           super
51:           changed
52:           notify_observers :observed_class_inherited, subclass
53:         end


Class: ActiveRecord::PreparedStatementInvalid

Class
ActiveRecord::PreparedStatementInvalid
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when number of bind variables in statement given to :condition key (for example, when using find method) does not match number of expected variables.

Example:

Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]

in example above two placeholders are given but only one variable to fill them.


Module: ActiveRecord::QueryCache

Module
ActiveRecord::QueryCache
In: activerecord/lib/active_record/query_cache.rb
Methods
  • cache
  • uncached
Public Instance methods
cache() {|| ...}

Enable the query cache within the block if Active Record is configured.

[ show source ]

    # File activerecord/lib/active_record/query_cache.rb, line 4
 4:     def cache(&block)
 5:       if ActiveRecord::Base.configurations.blank?
 6:         yield
 7:       else
 8:         connection.cache(&block)
 9:       end
10:     end
uncached() {|| ...}

Disable the query cache within the block if Active Record is configured.

[ show source ]

    # File activerecord/lib/active_record/query_cache.rb, line 13
13:     def uncached(&block)
14:       if ActiveRecord::Base.configurations.blank?
15:         yield
16:       else
17:         connection.uncached(&block)
18:       end
19:     end


Class: ActiveRecord::ReadOnlyRecord

Class
ActiveRecord::ReadOnlyRecord
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised on attempt to update record that is instantiated as read only.


Class: ActiveRecord::RecordNotFound

Class
ActiveRecord::RecordNotFound
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when ActiveRecord cannot find record by given id or set of ids.


Class: ActiveRecord::RecordNotSaved

Class
ActiveRecord::RecordNotSaved
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be saved because record is invalid.


Module: ActiveRecord::Reflection::ClassMethods

Module
ActiveRecord::Reflection::ClassMethods
In: activerecord/lib/active_record/reflection.rb

Reflection allows you to interrogate Active Record classes and objects about their associations and aggregations. This information can, for example, be used in a form builder that took an Active Record object and created input fields for all of the attributes depending on their type and displayed the associations to other objects.

You can find the interface for the AggregateReflection and AssociationReflection classes in the abstract MacroReflection class.

Methods
  • create_reflection
  • reflect_on_aggregation
  • reflect_on_all_aggregations
  • reflect_on_all_associations
  • reflect_on_association
  • reflections
Public Instance methods
create_reflection(macro, name, options, active_record)

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 13
13:       def create_reflection(macro, name, options, active_record)
14:         case macro
15:           when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
16:             reflection = AssociationReflection.new(macro, name, options, active_record)
17:           when :composed_of
18:             reflection = AggregateReflection.new(macro, name, options, active_record)
19:         end
20:         write_inheritable_hash :reflections, name => reflection
21:         reflection
22:       end
reflect_on_aggregation(aggregation)

Returns the AggregateReflection object for the named aggregation (use the symbol). Example:

  Account.reflect_on_aggregation(:balance) # returns the balance AggregateReflection

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 43
43:       def reflect_on_aggregation(aggregation)
44:         reflections[aggregation].is_a?(AggregateReflection) ? reflections[aggregation] : nil
45:       end
reflect_on_all_aggregations()

Returns an array of AggregateReflection objects for all the aggregations in the class.

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 35
35:       def reflect_on_all_aggregations
36:         reflections.values.select { |reflection| reflection.is_a?(AggregateReflection) }
37:       end
reflect_on_all_associations(macro = nil)

Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a certain association type, pass in the symbol (:has_many, :has_one, :belongs_to) for that as the first parameter. Example:

  Account.reflect_on_all_associations             # returns an array of all associations
  Account.reflect_on_all_associations(:has_many)  # returns an array of all has_many associations

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 54
54:       def reflect_on_all_associations(macro = nil)
55:         association_reflections = reflections.values.select { |reflection| reflection.is_a?(AssociationReflection) }
56:         macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
57:       end
reflect_on_association(association)

Returns the AssociationReflection object for the named association (use the symbol). Example:

  Account.reflect_on_association(:owner) # returns the owner AssociationReflection
  Invoice.reflect_on_association(:line_items).macro  # returns :has_many

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 64
64:       def reflect_on_association(association)
65:         reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
66:       end
reflections()

Returns a hash containing all AssociationReflection objects for the current class Example:

  Invoice.reflections
  Account.reflections

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 30
30:       def reflections
31:         read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {})
32:       end


Class: ActiveRecord::Reflection::MacroReflection

Class
ActiveRecord::Reflection::MacroReflection
In: | activerecord/lib/active_record/reflection.rb
Parent: | Object

Abstract base class for AggregateReflection and AssociationReflection that describes the interface available for both of those classes. Objects of AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.

Methods
  • ==
  • class_name
  • klass
  • macro
  • name
  • new
  • options
Attributes
[R] active_record
Public Class methods
new(macro, name, options, active_record)

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 75
75:       def initialize(macro, name, options, active_record)
76:         @macro, @name, @options, @active_record = macro, name, options, active_record
77:       end
Public Instance methods
==(other_aggregation)

[ show source ]

     # File activerecord/lib/active_record/reflection.rb, line 107
107:       def ==(other_aggregation)
108:         name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
109:       end
class_name()

[ show source ]

     # File activerecord/lib/active_record/reflection.rb, line 103
103:       def class_name
104:         @class_name ||= options[:class_name] || derive_class_name
105:       end
klass()

Returns the class for the macro, so "composed_of :balance, :class_name => ‘Money’" returns the Money class and "has_many :clients" returns the Client class.

[ show source ]

     # File activerecord/lib/active_record/reflection.rb, line 99
 99:       def klass
100:         @klass ||= class_name.constantize
101:       end
macro()

Returns the type of the macro, so it would return :composed_of for "composed_of :balance, :class_name => ‘Money’" or :has_many for "has_many :clients".

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 87
87:       def macro
88:         @macro
89:       end
name()

Returns the name of the macro, so it would return :balance for "composed_of :balance, :class_name => ‘Money’" or :clients for "has_many :clients".

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 81
81:       def name
82:         @name
83:       end
options()

Returns the hash of options used for the macro, so it would return { :class_name => "Money" } for "composed_of :balance, :class_name => ‘Money’" or {} for "has_many :clients".

[ show source ]

    # File activerecord/lib/active_record/reflection.rb, line 93
93:       def options
94:         @options
95:       end


Class: ActiveRecord::Rollback

Class
ActiveRecord::Rollback
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations. You can use it to roll your transaction back explicitly in the block passed to transaction method.


Class: ActiveRecord::Schema

Class
ActiveRecord::Schema
In: | activerecord/lib/active_record/schema.rb
Parent: | Migration

Allows programmers to programmatically define a schema in a portable DSL. This means you can define tables, indexes, etc. without using SQL directly, so your applications can more easily support multiple databases.

Usage:

  ActiveRecord::Schema.define do
    create_table :authors do |t|
      t.string :name, :null => false
    end

    add_index :authors, :name, :unique

    create_table :posts do |t|
      t.integer :author_id, :null => false
      t.string :subject
      t.text :body
      t.boolean :private, :default => false
    end

    add_index :posts, :author_id
  end

ActiveRecord::Schema is only supported by database adapters that also support migrations, the two features being very similar.

Methods
  • define
Public Class methods
define(info={}, &block)

Eval the given block. All methods available to the current connection adapter are available within the block, so you can easily use the database definition DSL to build up your schema (create_table, add_index, etc.).

The info hash is optional, and if given is used to define metadata about the current schema (like the schema‘s version):

  ActiveRecord::Schema.define(:version => 15) do
    ...
  end

[ show source ]

    # File activerecord/lib/active_record/schema.rb, line 42
42:     def self.define(info={}, &block)
43:       instance_eval(&block)
44:
45:       unless info.empty?
46:         initialize_schema_information
47:         cols = columns('schema_info')
48:
49:         info = info.map do |k,v|
50:           v = Base.connection.quote(v, cols.detect { |c| c.name == k.to_s })
51:           "#{k} = #{v}"
52:         end
53:
54:         Base.connection.update "UPDATE #{Migrator.schema_info_table_name} SET #{info.join(", ")}"
55:       end
56:     end


Module: ActiveRecord::Serialization

Module
ActiveRecord::Serialization
In: activerecord/lib/active_record/serialization.rb activerecord/lib/active_record/serializers/json_serializer.rb activerecord/lib/active_record/serializers/xml_serializer.rb
Methods
  • from_json
  • from_xml
  • to_json
  • to_xml
Public Instance methods
from_json(json)

[ show source ]

    # File activerecord/lib/active_record/serializers/json_serializer.rb, line 60
60:     def from_json(json)
61:       self.attributes = ActiveSupport::JSON.decode(json)
62:       self
63:     end
from_xml(xml)

[ show source ]

     # File activerecord/lib/active_record/serializers/xml_serializer.rb, line 128
128:     def from_xml(xml)
129:       self.attributes = Hash.from_xml(xml).values.first
130:       self
131:     end
to_json(options = {})

Returns a JSON string representing the model. Some configuration is available through options.

Without any options, the returned JSON string will include all the model‘s attributes. For example:

  konata = User.find(1)
  konata.to_json

  {"id": 1, "name": "Konata Izumi", "age": 16,
   "created_at": "2006/08/01", "awesome": true}

The :only and :except options can be used to limit the attributes included, and work similar to the attributes method. For example:

  konata.to_json(:only => [ :id, :name ])

  {"id": 1, "name": "Konata Izumi"}

  konata.to_json(:except => [ :id, :created_at, :age ])

  {"name": "Konata Izumi", "awesome": true}

To include any methods on the model, use :methods.

  konata.to_json(:methods => :permalink)

  {"id": 1, "name": "Konata Izumi", "age": 16,
   "created_at": "2006/08/01", "awesome": true,
   "permalink": "1-konata-izumi"}

To include associations, use :include.

  konata.to_json(:include => :posts)

  {"id": 1, "name": "Konata Izumi", "age": 16,
   "created_at": "2006/08/01", "awesome": true,
   "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
             {"id": 2, author_id: 1, "title": "So I was thinking"}]}

2nd level and higher order associations work as well:

  konata.to_json(:include => { :posts => {
                                 :include => { :comments => {
                                               :only => :body } },
                                 :only => :title } })

  {"id": 1, "name": "Konata Izumi", "age": 16,
   "created_at": "2006/08/01", "awesome": true,
   "posts": [{"comments": [{"body": "1st post!"}, {"body": "Second!"}],
              "title": "Welcome to the weblog"},
             {"comments": [{"body": "Don't think too hard"}],
              "title": "So I was thinking"}]}

[ show source ]

    # File activerecord/lib/active_record/serializers/json_serializer.rb, line 56
56:     def to_json(options = {})
57:       JsonSerializer.new(self, options).to_s
58:     end
to_xml(options = {}, &block)

Builds an XML document to represent the model. Some configuration is available through options, however more complicated cases should override ActiveRecord‘s to_xml.

By default the generated XML document will include the processing instruction and all object‘s attributes. For example:

  <?xml version="1.0" encoding="UTF-8"?>
  <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <id type="integer">1</id>
    <approved type="boolean">false</approved>
    <replies-count type="integer">0</replies-count>
    <bonus-time type="datetime">2000-01-01T08:28:00+12:00</bonus-time>
    <written-on type="datetime">2003-07-16T09:28:00+1200</written-on>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

This behavior can be controlled with :only, :except, :skip_instruct, :skip_types and :dasherize. The :only and :except options are the same as for the attributes method. The default is to dasherize all column names, to disable this, set :dasherize to false. To not have the column type included in the XML output, set :skip_types to true.

For instance:

  topic.to_xml(:skip_instruct => true, :except => [ :id, :bonus_time, :written_on, :replies_count ])

  <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <approved type="boolean">false</approved>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

To include first level associations use :include

  firm.to_xml :include => [ :account, :clients ]

  <?xml version="1.0" encoding="UTF-8"?>
  <firm>
    <id type="integer">1</id>
    <rating type="integer">1</rating>
    <name>37signals</name>
    <clients type="array">
      <client>
        <rating type="integer">1</rating>
        <name>Summit</name>
      </client>
      <client>
        <rating type="integer">1</rating>
        <name>Microsoft</name>
      </client>
    </clients>
    <account>
      <id type="integer">1</id>
      <credit-limit type="integer">50</credit-limit>
    </account>
  </firm>

To include any methods on the object(s) being called use :methods

  firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]

  <firm>
    # ... normal attributes as shown above ...
    <calculated-earnings>100000000000000000</calculated-earnings>
    <real-earnings>5</real-earnings>
  </firm>

To call any Proc‘s on the object(s) use :procs. The Proc‘s are passed a modified version of the options hash that was given to to_xml.

  proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
  firm.to_xml :procs => [ proc ]

  <firm>
    # ... normal attributes as shown above ...
    <abc>def</abc>
  </firm>

Alternatively, you can also just yield the builder object as part of the to_xml call:

  firm.to_xml do |xml|
    xml.creator do
      xml.first_name "David"
      xml.last_name "Heinemeier Hansson"
    end
  end

  <firm>
    # ... normal attributes as shown above ...
    <creator>
      <first_name>David</first_name>
      <last_name>Heinemeier Hansson</last_name>
    </creator>
  </firm>

You can override the to_xml method in your ActiveRecord::Base subclasses if you need to. The general form of doing this is

  class IHaveMyOwnXML < ActiveRecord::Base
    def to_xml(options = {})
      options[:indent] ||= 2
      xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
      xml.instruct! unless options[:skip_instruct]
      xml.level_one do
        xml.tag!(:second_level, 'content')
      end
    end
  end

[ show source ]

     # File activerecord/lib/active_record/serializers/xml_serializer.rb, line 123
123:     def to_xml(options = {}, &block)
124:       serializer = XmlSerializer.new(self, options)
125:       block_given? ? serializer.to_s(&block) : serializer.to_s
126:     end


Class: ActiveRecord::SerializationTypeMismatch

Class
ActiveRecord::SerializationTypeMismatch
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when unserialized object‘s type mismatches one specified for serializable field.


Class: ActiveRecord::StaleObjectError

Class
ActiveRecord::StaleObjectError
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised on attempt to save stale record. Record is stale when it‘s being saved in another query after instantiation, for example, when two users edit the same wiki page and one starts editing and saves the page before the other.

Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc.


Class: ActiveRecord::StatementInvalid

Class
ActiveRecord::StatementInvalid
In: | activerecord/lib/active_record/base.rb
Parent: | ActiveRecordError

Raised when SQL statement cannot be executed by the database (for example, it‘s often the case for MySQL when Ruby driver used is too old).


Module: ActiveRecord::Timestamp

Module
ActiveRecord::Timestamp
In: activerecord/lib/active_record/timestamp.rb

Active Record automatically timestamps create and update operations if the table has fields named created_at/created_on or updated_at/updated_on.

Timestamping can be turned off by setting

  <tt>ActiveRecord::Base.record_timestamps = false</tt>

Timestamps are in the local timezone by default but can use UTC by setting

  <tt>ActiveRecord::Base.default_timezone = :utc</tt>


Module: ActiveRecord::Transactions::ClassMethods

Module
ActiveRecord::Transactions::ClassMethods
In: activerecord/lib/active_record/transactions.rb

Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action. The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and vice versa. Transactions enforce the integrity of the database and guard the data against program errors or database break-downs. So basically you should use transaction blocks whenever you have a number of statements that must be executed together or not at all. Example:

  transaction do
    david.withdrawal(100)
    mary.deposit(100)
  end

This example will only take money from David and give to Mary if neither withdrawal nor deposit raises an exception. Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though, that the objects by default will not have their instance data returned to their pre-transactional state.

Different ActiveRecord classes in a single transaction

Though the transaction class method is called on some ActiveRecord class, the objects within the transaction block need not all be instances of that class. In this example a Balance record is transactionally saved even though transaction is called on the Account class:

  Account.transaction do
    balance.save!
    account.save!
  end

Transactions are not distributed across database connections

A transaction acts on a single database connection. If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:

  Student.transaction do
    Course.transaction do
      course.enroll(student)
      student.units += course.units
    end
  end

This is a poor solution, but full distributed transactions are beyond the scope of Active Record.

Save and destroy are automatically wrapped in a transaction

Both Base#save and Base#destroy come wrapped in a transaction that ensures that whatever you do in validations or callbacks will happen under the protected cover of a transaction. So you can use validations to check for values that the transaction depends on or you can raise exceptions in the callbacks to rollback.

Exception handling

Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you should be ready to catch those in your application code. One exception is the ActiveRecord::Rollback exception, which will trigger a ROLLBACK when raised, but not be re-raised by the transaction block.

Methods
  • transaction
Public Instance methods
transaction(&block)

[ show source ]

    # File activerecord/lib/active_record/transactions.rb, line 75
75:       def transaction(&block)
76:         previous_handler = trap('TERM') { raise TransactionError, "Transaction aborted" }
77:         increment_open_transactions
78:
79:         begin
80:           connection.transaction(Thread.current['start_db_transaction'], &block)
81:         ensure
82:           decrement_open_transactions
83:           trap('TERM', previous_handler)
84:         end
85:       end


Module: ActiveRecord::Validations

Module
ActiveRecord::Validations
In: activerecord/lib/active_record/validations.rb

Active Records implement validation by overwriting Base#validate (or the variations, validate_on_create and validate_on_update). Each of these methods can inspect the state of the object, which usually means ensuring that a number of attributes have a certain value (such as not empty, within a given range, matching a certain regular expression).

Example:

  class Person < ActiveRecord::Base
    protected
      def validate
        errors.add_on_empty %w( first_name last_name )
        errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
      end

      def validate_on_create # is only run the first time a new object is saved
        unless valid_discount?(membership_discount)
          errors.add("membership_discount", "has expired")
        end
      end

      def validate_on_update
        errors.add_to_base("No changes have occurred") if unchanged_attributes?
      end
  end

  person = Person.new("first_name" => "David", "phone_number" => "what?")
  person.save                         # => false (and doesn't do the save)
  person.errors.empty?                # => false
  person.errors.count                 # => 2
  person.errors.on "last_name"        # => "can't be empty"
  person.errors.on "phone_number"     # => "has invalid format"
  person.errors.each_full { |msg| puts msg }
                                      # => "Last name can't be empty\n" +
                                           "Phone number has invalid format"

  person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" }
  person.save # => true (and person is now saved in the database)

An Errors object is automatically created for every Active Record.

Please do have a look at ActiveRecord::Validations::ClassMethods for a higher level of validations.

Methods
  • errors
  • save_with_validation
  • save_with_validation!
  • update_attribute_with_validation_skipping
  • valid?
  • validate
  • validate_on_create
  • validate_on_update
Classes and Modules
Module ActiveRecord::Validations::ClassMethods
Constants
VALIDATIONS = %w( validate validate_on_create validate_on_update )
Public Instance methods
errors()

Returns the Errors object that holds all information about attribute error messages.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 977
977:     def errors
978:       @errors ||= Errors.new(self)
979:     end
save_with_validation(perform_validation = true)

The validation process on save can be skipped by passing false. The regular Base#save method is replaced with this when the validations module is mixed in, which it is by default.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 932
932:     def save_with_validation(perform_validation = true)
933:       if perform_validation && valid? || !perform_validation
934:         save_without_validation
935:       else
936:         false
937:       end
938:     end
save_with_validation!()

Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false if the record is not valid.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 942
942:     def save_with_validation!
943:       if valid?
944:         save_without_validation!
945:       else
946:         raise RecordInvalid.new(self)
947:       end
948:     end
update_attribute_with_validation_skipping(name, value)

Updates a single attribute and saves the record without going through the normal validation procedure. This is especially useful for boolean flags on existing records. The regular update_attribute method in Base is replaced with this when the validations module is mixed in, which it is by default.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 953
953:     def update_attribute_with_validation_skipping(name, value)
954:       send(name.to_s + '=', value)
955:       save(false)
956:     end
valid?()

Runs validate and validate_on_create or validate_on_update and returns true if no errors were added otherwise false.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 959
959:     def valid?
960:       errors.clear
961:
962:       run_validations(:validate)
963:       validate
964:
965:       if new_record?
966:         run_validations(:validate_on_create)
967:         validate_on_create
968:       else
969:         run_validations(:validate_on_update)
970:         validate_on_update
971:       end
972:
973:       errors.empty?
974:     end
Protected Instance methods
validate(

Overwrite this method for validation checks on all saves and use Errors.add(field, msg) for invalid attributes.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 983
983:       def validate #:doc:
984:       end
validate_on_create(

Overwrite this method for validation checks used only on creation.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 987
987:       def validate_on_create #:doc:
988:       end
validate_on_update(

Overwrite this method for validation checks used only on updates.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 991
991:       def validate_on_update # :doc:
992:       end


Module: ActiveRecord::Validations::ClassMethods

Module
ActiveRecord::Validations::ClassMethods
In: activerecord/lib/active_record/validations.rb

All of the following validations are defined in the class scope of the model that you‘re interested in validating. They offer a more declarative way of specifying when the model is valid and when it is not. It is recommended to use these over the low-level calls to validate and validate_on_create when possible.

Methods
  • condition_block?
  • create!
  • evaluate_condition
  • validate
  • validate_on_create
  • validate_on_update
  • validates_acceptance_of
  • validates_associated
  • validates_confirmation_of
  • validates_each
  • validates_exclusion_of
  • validates_format_of
  • validates_inclusion_of
  • validates_length_of
  • validates_numericality_of
  • validates_presence_of
  • validates_size_of
  • validates_uniqueness_of
Constants
DEFAULT_VALIDATION_OPTIONS | = | { :on => :save, :allow_nil => false, :allow_blank => false, :message => nil
ALL_RANGE_OPTIONS | = | [ :is, :within, :in, :minimum, :maximum ].freeze
ALL_NUMERICALITY_CHECKS | = | { :greater_than => '>', :greater_than_or_equal_to => '>=', :equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=', :odd => 'odd?', :even => 'even?' }.freeze
Public Instance methods
condition_block?(condition)

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 342
342:       def condition_block?(condition)
343:         condition.respond_to?("call") && (condition.arity == 1 || condition.arity == -1)
344:       end
create!(attributes = nil)

Creates an object just like Base.create but calls save! instead of save so an exception is raised if the record is invalid.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 904
904:       def create!(attributes = nil)
905:         if attributes.is_a?(Array)
906:           attributes.collect { |attr| create!(attr) }
907:         else
908:           object = new(attributes)
909:           object.save!
910:           object
911:         end
912:       end
evaluate_condition(condition, record)

Determine from the given condition (whether a block, procedure, method or string) whether or not to validate the record. See validates_each.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 348
348:       def evaluate_condition(condition, record)
349:         case condition
350:           when Symbol; record.send(condition)
351:           when String; eval(condition, record.send(:binding))
352:           else
353:             if condition_block?(condition)
354:               condition.call(record)
355:             else
356:               raise(
357:                 ActiveRecordError,
358:                 "Validations need to be either a symbol, string (to be eval'ed), proc/method, or " +
359:                 "class implementing a static validation method"
360:               )
361:             end
362:           end
363:       end
validate(*methods, &block)

Adds a validation method or block to the class. This is useful when overriding the validate instance method becomes too unwieldly and you‘re looking for more descriptive declaration of your validations.

This can be done with a symbol pointing to a method:

  class Comment < ActiveRecord::Base
    validate :must_be_friends

    def must_be_friends
      errors.add_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
    end
  end

Or with a block which is passed the current record to be validated:

  class Comment < ActiveRecord::Base
    validate do |comment|
      comment.must_be_friends
    end

    def must_be_friends
      errors.add_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
    end
  end

This usage applies to validate_on_create and validate_on_update as well.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 327
327:       def validate(*methods, &block)
328:         methods << block if block_given?
329:         write_inheritable_set(:validate, methods)
330:       end
validate_on_create(*methods, &block)

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 332
332:       def validate_on_create(*methods, &block)
333:         methods << block if block_given?
334:         write_inheritable_set(:validate_on_create, methods)
335:       end
validate_on_update(*methods, &block)

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 337
337:       def validate_on_update(*methods, &block)
338:         methods << block if block_given?
339:         write_inheritable_set(:validate_on_update, methods)
340:       end
validates_acceptance_of(*attr_names)

Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:

  class Person < ActiveRecord::Base
    validates_acceptance_of :terms_of_service
    validates_acceptance_of :eula, :message => "must be abided"
  end

If the database column does not exist, the terms_of_service attribute is entirely virtual. This check is performed only if terms_of_service is not nil and by default on save.

Configuration options:

  • message - A custom error message (default is: "must be accepted")
  • on - Specifies when this validation is active (default is :save, other options :create, :update)
  • allow_nil - Skip validation if attribute is nil. (default is true)
  • accept - Specifies value that is considered accepted. The default value is a string "1", which makes it easy to relate to an HTML checkbox. This should be set to ‘true’ if you are validating a database column, since the attribute is typecast from "1" to true before validation.
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 462
462:       def validates_acceptance_of(*attr_names)
463:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }
464:         configuration.update(attr_names.extract_options!)
465:
466:         db_cols = begin
467:           column_names
468:         rescue ActiveRecord::StatementInvalid
469:           []
470:         end
471:         names = attr_names.reject { |name| db_cols.include?(name.to_s) }
472:         attr_accessor(*names)
473:
474:         validates_each(attr_names,configuration) do |record, attr_name, value|
475:           record.errors.add(attr_name, configuration[:message]) unless value == configuration[:accept]
476:         end
477:       end
validates_associated(*attr_names)

Validates whether the associated object or objects are all valid themselves. Works with any kind of association.

  class Book < ActiveRecord::Base
    has_many :pages
    belongs_to :library

    validates_associated :pages, :library
  end

Warning: If, after the above definition, you then wrote:

  class Page < ActiveRecord::Base
    belongs_to :book

    validates_associated :book
  end

…this would specify a circular dependency and cause infinite recursion.

NOTE: This validation will not fail if the association hasn‘t been assigned. If you want to ensure that the association is both present and guaranteed to be valid, you also need to use validates_presence_of.

Configuration options:

  • message - A custom error message (default is: "is invalid")
  • on Specifies when this validation is active (default is :save, other options :create, :update)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 824
824:       def validates_associated(*attr_names)
825:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
826:         configuration.update(attr_names.extract_options!)
827:
828:         validates_each(attr_names, configuration) do |record, attr_name, value|
829:           record.errors.add(attr_name, configuration[:message]) unless
830:             (value.is_a?(Array) ? value : [value]).inject(true) { |v, r| (r.nil? || r.valid?) && v }
831:         end
832:       end
validates_confirmation_of(*attr_names)

Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:

  Model:
    class Person < ActiveRecord::Base
      validates_confirmation_of :user_name, :password
      validates_confirmation_of :email_address, :message => "should match confirmation"
    end

  View:
    <%= password_field "person", "password" %>
    <%= password_field "person", "password_confirmation" %>

The added password_confirmation attribute is virtual; it exists only as an in-memory attribute for validating the password. To achieve this, the validation adds acccessors to the model for the confirmation attribute. NOTE: This check is performed only if password_confirmation is not nil, and by default only on save. To require confirmation, make sure to add a presence check for the confirmation attribute:

  validates_presence_of :password_confirmation, :if => :password_changed?

Configuration options:

  • message - A custom error message (default is: "doesn‘t match confirmation")
  • on - Specifies when this validation is active (default is :save, other options :create, :update)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 428
428:       def validates_confirmation_of(*attr_names)
429:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
430:         configuration.update(attr_names.extract_options!)
431:
432:         attr_accessor(*(attr_names.map { |n| "#{n}_confirmation" }))
433:
434:         validates_each(attr_names, configuration) do |record, attr_name, value|
435:           record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation")
436:         end
437:       end
validates_each(*attrs) {|record, attr, value| ...}

Validates each attribute against a block.

  class Person < ActiveRecord::Base
    validates_each :first_name, :last_name do |record, attr, value|
      record.errors.add attr, 'starts with z.' if value[0] == ?z
    end
  end

Options:

  • on - Specifies when this validation is active (default is :save, other options :create, :update)
  • allow_nil - Skip validation if attribute is nil.
  • allow_blank - Skip validation if attribute is blank.
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 383
383:       def validates_each(*attrs)
384:         options = attrs.extract_options!.symbolize_keys
385:         attrs   = attrs.flatten
386:
387:         # Declare the validation.
388:         send(validation_method(options[:on] || :save)) do |record|
389:           # Don't validate when there is an :if condition and that condition is false or there is an :unless condition and that condition is true
390:           unless (options[:if] && !evaluate_condition(options[:if], record)) || (options[:unless] && evaluate_condition(options[:unless], record))
391:             attrs.each do |attr|
392:               value = record.send(attr)
393:               next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
394:               yield record, attr, value
395:             end
396:           end
397:         end
398:       end
validates_exclusion_of(*attr_names)

Validates that the value of the specified attribute is not in a particular enumerable object.

  class Person < ActiveRecord::Base
    validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
    validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
    validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %s is not allowed"
  end

Configuration options:

  • in - An enumerable object of items that the value shouldn‘t be part of
  • message - Specifies a customer error message (default is: "is reserved")
  • allow_nil - If set to true, skips this validation if the attribute is null (default is: false)
  • allow_blank - If set to true, skips this validation if the attribute is blank (default is: false)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 780
780:       def validates_exclusion_of(*attr_names)
781:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save }
782:         configuration.update(attr_names.extract_options!)
783:
784:         enum = configuration[:in] || configuration[:within]
785:
786:         raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
787:
788:         validates_each(attr_names, configuration) do |record, attr_name, value|
789:           record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value)
790:         end
791:       end
validates_format_of(*attr_names)

Validates whether the value of the specified attribute is of the correct form by matching it against the regular expression provided.

  class Person < ActiveRecord::Base
    validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
  end

Note: use \A and \Z to match the start and end of the string, ^ and $ match the start/end of a line.

A regular expression must be provided or else an exception will be raised.

Configuration options:

  • message - A custom error message (default is: "is invalid")
  • with - The regular expression used to validate the format with (note: must be supplied!)
  • on Specifies when this validation is active (default is :save, other options :create, :update)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 718
718:       def validates_format_of(*attr_names)
719:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
720:         configuration.update(attr_names.extract_options!)
721:
722:         raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp)
723:
724:         validates_each(attr_names, configuration) do |record, attr_name, value|
725:           record.errors.add(attr_name, configuration[:message]) unless value.to_s =~ configuration[:with]
726:         end
727:       end
validates_inclusion_of(*attr_names)

Validates whether the value of the specified attribute is available in a particular enumerable object.

  class Person < ActiveRecord::Base
    validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!"
    validates_inclusion_of :age, :in => 0..99
    validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list"
  end

Configuration options:

  • in - An enumerable object of available items
  • message - Specifies a customer error message (default is: "is not included in the list")
  • allow_nil - If set to true, skips this validation if the attribute is null (default is: false)
  • allow_blank - If set to true, skips this validation if the attribute is blank (default is: false)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 748
748:       def validates_inclusion_of(*attr_names)
749:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
750:         configuration.update(attr_names.extract_options!)
751:
752:         enum = configuration[:in] || configuration[:within]
753:
754:         raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
755:
756:         validates_each(attr_names, configuration) do |record, attr_name, value|
757:           record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value)
758:         end
759:       end
validates_length_of(*attrs)

Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:

  class Person < ActiveRecord::Base
    validates_length_of :first_name, :maximum=>30
    validates_length_of :last_name, :maximum=>30, :message=>"less than %d if you don't mind"
    validates_length_of :fax, :in => 7..32, :allow_nil => true
    validates_length_of :phone, :in => 7..32, :allow_blank => true
    validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
    validates_length_of :fav_bra_size, :minimum=>1, :too_short=>"please enter at least %d character"
    validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me."
  end

Configuration options:

  • minimum - The minimum size of the attribute
  • maximum - The maximum size of the attribute
  • is - The exact size of the attribute
  • within - A range specifying the minimum and maximum size of the attribute
  • in - A synonym(or alias) for :within
  • allow_nil - Attribute may be nil; skip validation.
  • allow_blank - Attribute may be blank; skip validation.
  • too_long - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)")
  • too_short - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)")
  • wrong_length - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)")
  • message - The error message to use for a :minimum, :maximum, or :is violation. An alias of the appropriate too_long/too_short/wrong_length message
  • on - Specifies when this validation is active (default is :save, other options :create, :update)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.
This method is also aliased as validates_size_of

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 557
557:       def validates_length_of(*attrs)
558:         # Merge given options with defaults.
559:         options = {
560:           :too_long     => ActiveRecord::Errors.default_error_messages[:too_long],
561:           :too_short    => ActiveRecord::Errors.default_error_messages[:too_short],
562:           :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
563:         }.merge(DEFAULT_VALIDATION_OPTIONS)
564:         options.update(attrs.extract_options!.symbolize_keys)
565:
566:         # Ensure that one and only one range option is specified.
567:         range_options = ALL_RANGE_OPTIONS & options.keys
568:         case range_options.size
569:           when 0
570:             raise ArgumentError, 'Range unspecified.  Specify the :within, :maximum, :minimum, or :is option.'
571:           when 1
572:             # Valid number of options; do nothing.
573:           else
574:             raise ArgumentError, 'Too many range options specified.  Choose only one.'
575:         end
576:
577:         # Get range option and value.
578:         option = range_options.first
579:         option_value = options[range_options.first]
580:
581:         case option
582:           when :within, :in
583:             raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
584:
585:             too_short = options[:too_short] % option_value.begin
586:             too_long  = options[:too_long]  % option_value.end
587:
588:             validates_each(attrs, options) do |record, attr, value|
589:               if value.nil? or value.split(//).size < option_value.begin
590:                 record.errors.add(attr, too_short)
591:               elsif value.split(//).size > option_value.end
592:                 record.errors.add(attr, too_long)
593:               end
594:             end
595:           when :is, :minimum, :maximum
596:             raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
597:
598:             # Declare different validations per option.
599:             validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
600:             message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
601:
602:             message = (options[:message] || options[message_options[option]]) % option_value
603:
604:             validates_each(attrs, options) do |record, attr, value|
605:               if value.kind_of?(String)
606:                 record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
607:               else
608:                 record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
609:               end
610:             end
611:         end
612:       end
validates_numericality_of(*attr_names)

Validates whether the value of the specified attribute is numeric by trying to convert it to a float with Kernel.Float (if integer is false) or applying it to the regular expression /\A[+\-]?\d+\Z/ (if integer is set to true).

  class Person < ActiveRecord::Base
    validates_numericality_of :value, :on => :create
  end

Configuration options:

  • message - A custom error message (default is: "is not a number")
  • on Specifies when this validation is active (default is :save, other options :create, :update)
  • only_integer Specifies whether the value has to be an integer, e.g. an integral value (default is false)
  • allow_nil Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil
  • greater_than Specifies the value must be greater than the supplied value
  • greater_than_or_equal_to Specifies the value must be greater than or equal the supplied value
  • equal_to Specifies the value must be equal to the supplied value
  • less_than Specifies the value must be less than the supplied value
  • less_than_or_equal_to Specifies the value must be less than or equal the supplied value
  • odd Specifies the value must be an odd number
  • even Specifies the value must be an even number
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 860
860:       def validates_numericality_of(*attr_names)
861:         configuration = { :on => :save, :only_integer => false, :allow_nil => false }
862:         configuration.update(attr_names.extract_options!)
863:
864:
865:         numericality_options = ALL_NUMERICALITY_CHECKS.keys & configuration.keys
866:
867:         (numericality_options - [ :odd, :even ]).each do |option|
868:           raise ArgumentError, ":#{option} must be a number" unless configuration[option].is_a?(Numeric)
869:         end
870:
871:         validates_each(attr_names,configuration) do |record, attr_name, value|
872:           raw_value = record.send("#{attr_name}_before_type_cast") || value
873:
874:           next if configuration[:allow_nil] and raw_value.nil?
875:
876:           if configuration[:only_integer]
877:             unless raw_value.to_s =~ /\A[+-]?\d+\Z/
878:               record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
879:               next
880:             end
881:             raw_value = raw_value.to_i
882:           else
883:            begin
884:               raw_value = Kernel.Float(raw_value.to_s)
885:             rescue ArgumentError, TypeError
886:               record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
887:               next
888:             end
889:           end
890:
891:           numericality_options.each do |option|
892:             case option
893:               when :odd, :even
894:                 record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[option]) unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[]
895:               else
896:                 record.errors.add(attr_name, configuration[:message] || (ActiveRecord::Errors.default_error_messages[option] % configuration[option])) unless raw_value.method(ALL_NUMERICALITY_CHECKS[option])[configuration[option]]
897:             end
898:           end
899:         end
900:       end
validates_presence_of(*attr_names)

Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:

  class Person < ActiveRecord::Base
    validates_presence_of :first_name
  end

The first_name attribute must be in the object and it cannot be blank.

If you want to validate the presence of a boolean field (where the real values are true and false), you will want to use validates_inclusion_of :field_name, :in => [true, false] This is due to the way Object#blank? handles boolean values. false.blank? # => true

Configuration options:

  • message - A custom error message (default is: "can‘t be blank")
  • on - Specifies when this validation is active (default is :save, other options :create, :update)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => 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:

 validates_presence_of :invoice_id

Not this:

 validates_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.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 512
512:       def validates_presence_of(*attr_names)
513:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save }
514:         configuration.update(attr_names.extract_options!)
515:
516:         # can't use validates_each here, because it cannot cope with nonexistent attributes,
517:         # while errors.add_on_empty can
518:         send(validation_method(configuration[:on])) do |record|
519:           unless (configuration[:if] && !evaluate_condition(configuration[:if], record)) || (configuration[:unless] && evaluate_condition(configuration[:unless], record))
520:             record.errors.add_on_blank(attr_names, configuration[:message])
521:           end
522:         end
523:       end
validates_size_of(*attrs)

Alias for validates_length_of

validates_uniqueness_of(*attr_names)

Validates whether the value of the specified attributes are unique across the system. Useful for making sure that only one user can be named "davidhh".

  class Person < ActiveRecord::Base
    validates_uniqueness_of :user_name, :scope => :account_id
  end

It can also validate whether the value of the specified attributes are unique based on multiple scope parameters. For example, making sure that a teacher can only be on the schedule once per semester for a particular class.

  class TeacherSchedule < ActiveRecord::Base
    validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id]
  end

When the record is created, a check is performed to make sure that no record exists in the database with the given value for the specified attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself.

Because this check is performed outside the database there is still a chance that duplicate values will be inserted in two parallel transactions. To guarantee against this you should create a unique index on the field. See create_index for more information.

Configuration options:

  • message - Specifies a custom error message (default is: "has already been taken")
  • scope - One or more columns by which to limit the scope of the uniquness constraint.
  • case_sensitive - Looks for an exact match. Ignored by non-text columns (true by default).
  • allow_nil - If set to true, skips this validation if the attribute is null (default is: false)
  • allow_blank - If set to true, skips this validation if the attribute is blank (default is: false)
  • if - 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.
  • unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.

[ show source ]

     # File activerecord/lib/active_record/validations.rb, line 650
650:       def validates_uniqueness_of(*attr_names)
651:         configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true }
652:         configuration.update(attr_names.extract_options!)
653:
654:         validates_each(attr_names,configuration) do |record, attr_name, value|
655:           if value.nil? || (configuration[:case_sensitive] || !columns_hash[attr_name.to_s].text?)
656:             condition_sql = "#{record.class.table_name}.#{attr_name} #{attribute_condition(value)}"
657:             condition_params = [value]
658:           else
659:             condition_sql = "LOWER(#{record.class.table_name}.#{attr_name}) #{attribute_condition(value)}"
660:             condition_params = [value.downcase]
661:           end
662:
663:           if scope = configuration[:scope]
664:             Array(scope).map do |scope_item|
665:               scope_value = record.send(scope_item)
666:               condition_sql << " AND #{record.class.table_name}.#{scope_item} #{attribute_condition(scope_value)}"
667:               condition_params << scope_value
668:             end
669:           end
670:
671:           unless record.new_record?
672:             condition_sql << " AND #{record.class.table_name}.#{record.class.primary_key} <> ?"
673:             condition_params << record.send(:id)
674:           end
675:
676:           # The check for an existing value should be run from a class that
677:           # isn't abstract. This means working down from the current class
678:           # (self), to the first non-abstract class. Since classes don't know
679:           # their subclasses, we have to build the hierarchy between self and
680:           # the record's class.
681:           class_hierarchy = [record.class]
682:           while class_hierarchy.first != self
683:             class_hierarchy.insert(0, class_hierarchy.first.superclass)
684:           end
685:
686:           # Now we can work our way down the tree to the first non-abstract
687:           # class (which has a database table to query from).
688:           finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? }
689:
690:           if finder_class.find(:first, :conditions => [condition_sql, *condition_params])
691:             record.errors.add(attr_name, configuration[:message])
692:           end
693:         end
694:       end


File: aggregations.rb

File
aggregations.rb
Path: | activerecord/lib/active_record/aggregations.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: associations.rb

File
associations.rb
Path: | activerecord/lib/active_record/associations.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/associations/association_proxy
  • active_record/associations/association_collection
  • active_record/associations/belongs_to_association
  • active_record/associations/belongs_to_polymorphic_association
  • active_record/associations/has_one_association
  • active_record/associations/has_many_association
  • active_record/associations/has_many_through_association
  • active_record/associations/has_and_belongs_to_many_association


File: association_collection.rb

File
association_collection.rb
Path: | activerecord/lib/active_record/associations/association_collection.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • set


File: association_proxy.rb

File
association_proxy.rb
Path: | activerecord/lib/active_record/associations/association_proxy.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: belongs_to_association.rb

File
belongs_to_association.rb
Path: | activerecord/lib/active_record/associations/belongs_to_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: belongs_to_polymorphic_association.rb

File
belongs_to_polymorphic_association.rb
Path: | activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: has_and_belongs_to_many_association.rb

File
has_and_belongs_to_many_association.rb
Path: | activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: has_many_association.rb

File
has_many_association.rb
Path: | activerecord/lib/active_record/associations/has_many_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: has_many_through_association.rb

File
has_many_through_association.rb
Path: | activerecord/lib/active_record/associations/has_many_through_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: has_one_association.rb

File
has_one_association.rb
Path: | activerecord/lib/active_record/associations/has_one_association.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: attribute_methods.rb

File
attribute_methods.rb
Path: | activerecord/lib/active_record/attribute_methods.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: base.rb

File
base.rb
Path: | activerecord/lib/active_record/base.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • base64
  • yaml
  • set


File: calculations.rb

File
calculations.rb
Path: | activerecord/lib/active_record/calculations.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: callbacks.rb

File
callbacks.rb
Path: | activerecord/lib/active_record/callbacks.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • observer


File: connection_specification.rb

File
connection_specification.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • set
  • rubygems


File: database_statements.rb

File
database_statements.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: query_cache.rb

File
query_cache.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: quoting.rb

File
quoting.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: schema_definitions.rb

File
schema_definitions.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • date
  • bigdecimal
  • bigdecimal/util


File: schema_statements.rb

File
schema_statements.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: abstract_adapter.rb

File
abstract_adapter.rb
Path: | activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • benchmark
  • date
  • bigdecimal
  • bigdecimal/util
  • active_record/connection_adapters/abstract/schema_definitions
  • active_record/connection_adapters/abstract/schema_statements
  • active_record/connection_adapters/abstract/database_statements
  • active_record/connection_adapters/abstract/quoting
  • active_record/connection_adapters/abstract/connection_specification
  • active_record/connection_adapters/abstract/query_cache


File: fixtures.rb

File
fixtures.rb
Path: | activerecord/lib/active_record/fixtures.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • erb
  • yaml
  • csv


File: optimistic.rb

File
optimistic.rb
Path: | activerecord/lib/active_record/locking/optimistic.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: pessimistic.rb

File
pessimistic.rb
Path: | activerecord/lib/active_record/locking/pessimistic.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Copyright (c) 2006 Shugo Maeda <shugo@ruby-lang.org>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


File: migration.rb

File
migration.rb
Path: | activerecord/lib/active_record/migration.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: observer.rb

File
observer.rb
Path: | activerecord/lib/active_record/observer.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • singleton
  • set


File: query_cache.rb

File
query_cache.rb
Path: | activerecord/lib/active_record/query_cache.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: reflection.rb

File
reflection.rb
Path: | activerecord/lib/active_record/reflection.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: schema.rb

File
schema.rb
Path: | activerecord/lib/active_record/schema.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: schema_dumper.rb

File
schema_dumper.rb
Path: | activerecord/lib/active_record/schema_dumper.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • stringio
  • bigdecimal


File: serialization.rb

File
serialization.rb
Path: | activerecord/lib/active_record/serialization.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/serializers/xml_serializer
  • active_record/serializers/json_serializer


File: json_serializer.rb

File
json_serializer.rb
Path: | activerecord/lib/active_record/serializers/json_serializer.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: xml_serializer.rb

File
xml_serializer.rb
Path: | activerecord/lib/active_record/serializers/xml_serializer.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: timestamp.rb

File
timestamp.rb
Path: | activerecord/lib/active_record/timestamp.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: transactions.rb

File
transactions.rb
Path: | activerecord/lib/active_record/transactions.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • thread


File: validations.rb

File
validations.rb
Path: | activerecord/lib/active_record/validations.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: version.rb

File
version.rb
Path: | activerecord/lib/active_record/version.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008


File: CHANGELOG

File
CHANGELOG
Path: | activerecord/CHANGELOG
Modified: | Sun Mar 02 11:08:51 -0700 2008

*2.0.2* (December 16th, 2007)

  • Ensure optimistic locking handles nil lock_version values properly. Closes 10510 [rick]
  • Make the Fixtures Test::Unit enhancements more supporting for double-loaded test cases. Closes 10379 [brynary]
  • Fix that validates_acceptance_of still works for non-existent tables (useful for bootstrapping new databases). Closes 10474 [hasmanyjosh]
  • Ensure that the :uniq option for has_many :through associations retains the order. 10463 [remvee]
  • Base.exists? doesn‘t rescue exceptions to avoid hiding SQL errors. 10458 [Michael Klishin]
  • Documentation: Active Record exceptions, destroy_all and delete_all. 10444, 10447 [Michael Klishin]

*2.0.1* (December 7th, 2007)

  • Removed query cache rescue as it could cause code to be run twice (closes 10408) [DHH]

*2.0.0* (December 6th, 2007)

  • Anchor DateTimeTest to fixed DateTime instead of a variable value based on Time.now#advance#to_datetime, so that this test passes on 64-bit platforms running Ruby 1.8.6+ [Geoff Buesing]
  • Fixed that the Query Cache should just be ignored if the database is misconfigured (so that the "About your applications environment" works even before the database has been created) [DHH]
  • Fixed that the truncation of strings longer than 50 chars should use inspect

so newlines etc are escaped 10385 [Norbert Crombach]

  • Fixed that habtm associations should be able to set :select as part of their definition and have that honored [DHH]
  • Document how the :include option can be used in Calculations::calculate. Closes 7446 [adamwiggins, ultimoamore]
  • Fix typo in documentation for polymorphic associations w/STI. Closes 7461 [johnjosephbachir]
  • Reveal that the type option in migrations can be any supported column type for your database but also include caveat about agnosticism. Closes 7531 [adamwiggins, mikong]
  • More complete documentation for find_by_sql. Closes 7912 [fearoffish]
  • Added ActiveRecord::Base#becomes to turn a record into one of another class (mostly relevant for STIs) [DHH]. Example:
      render :partial => @client.becomes(Company) # renders companies/company instead of clients/client
  • Fixed that to_xml should not automatically pass :procs to associations included with :include 10162 [Cheah Chu Yeow]
  • Fix documentation typo introduced in [8250]. Closes 10339 [Henrik N]
  • Foxy fixtures: support single-table inheritance. 10234 [tom]
  • Foxy fixtures: allow mixed usage to make migration easier and more attractive. 10004 [lotswholetime]
  • Make the record_timestamps class-inheritable so it can be set per model. 10004 [tmacedo]
  • Allow validates_acceptance_of to use a real attribute instead of only virtual (so you can record that the acceptance occured) 7457 [ambethia]
  • DateTimes use Ruby‘s default calendar reform setting. 10201 [Geoff Buesing]
  • Dynamic finders on association collections respect association :order and :limit. 10211, 10227 [Patrick Joyce, Rick Olson, Jack Danger Canty]
  • Add ‘foxy’ support for fixtures of polymorphic associations. 10183 [jbarnette, David Lowenfels]
  • validates_inclusion_of and validates_exclusion_of allow formatted :message strings. 8132 [devrieda, Mike Naberezny]
  • attr_readonly behaves well with optimistic locking. 10188 [Nick Bugajski]
  • Base#to_xml supports the nil="true" attribute like Hash#to_xml. 8268 [Catfish]
  • Change plings to the more conventional quotes in the documentation. Closes 10104 [danger]
  • Fix HasManyThrough Association so it uses :conditions on the HasMany Association. Closes 9729 [danger]
  • Ensure that column names are quoted. Closes 10134 [wesley.moxam]
  • Smattering of grammatical fixes to documentation. Closes 10083 [BobSilva]
  • Enhance explanation with more examples for attr_accessible macro. Closes 8095 [fearoffish, Marcel Molina]
  • Update association/method mapping table to refected latest collection methods for has_many :through. Closes 8772 [Pratik Naik]
  • Explain semantics of having several different AR instances in a transaction block. Closes 9036 [jacobat, Marcel Molina]
  • Update Schema documentation to use updated sexy migration notation. Closes 10086 [sjgman9]
  • Make fixtures work with the new test subclasses. [Tarmo Tänav, Koz]
  • Introduce finder :joins with associations. Same :include syntax but with inner rather than outer joins. 10012 [RubyRedRick]
      # Find users with an avatar
  User.find(:all, :joins => :avatar)

  # Find posts with a high-rated comment.
  Post.find(:all, :joins => :comments, :conditions => 'comments.rating > 3')
  • Associations: speedup duplicate record check. 10011 [Pratik Naik]
  • Make sure that << works on has_many associations on unsaved records. Closes 9989 [hasmanyjosh]
  • Allow association redefinition in subclasses. 9346 [wildchild]
  • Fix has_many :through delete with custom foreign keys. 6466 [naffis]
  • Foxy fixtures, from rathole (svn.geeksomnia.com/rathole/trunk/README)
      - stable, autogenerated IDs
  - specify associations (belongs_to, has_one, has_many) by label, not ID
  - specify HABTM associations as inline lists
  - autofill timestamp columns
  - support YAML defaults
  - fixture label interpolation

    Enabled for fixtures that correspond to a model class and don‘t specify a primary key value. 9981 [jbarnette]

  • Add docs explaining how to protect all attributes using attr_accessible with no arguments. Closes 9631 [boone, rmm5t]
  • Update add_index documentation to use new options api. Closes 9787 [Kamal Fariz Mahyuddin]
  • Allow find on a has_many association defined with :finder_sql to accept id arguments as strings like regular find does. Closes 9916 [krishna]
  • Use VALID_FIND_OPTIONS when resolving :find scoping rather than hard coding the list of valid find options. Closes 9443 [sur]
  • Limited eager loading no longer ignores scoped :order. Closes 9561 [danger, Josh Peek]
  • Assigning an instance of a foreign class to a composed_of aggregate calls an optional conversion block. Refactor and simplify composed_of implementation. 6322 [brandon, Chris Cruft]
  • Assigning nil to a composed_of aggregate also sets its immediate value to nil. 9843 [Chris Cruft]
  • Ensure that mysql quotes table names with database names correctly. Closes 9911 [crayz]

    "foo.bar" => "`foo`.`bar`"

  • Complete the assimilation of Sexy Migrations from ErrFree [Chris Wanstrath, PJ Hyett]
          http://errtheblog.com/post/2381
  • Qualified column names work in hash conditions, like :conditions => { ‘comments.created_at’ => … }. 9733 [danger]
  • Fix regression where the association would not construct new finder SQL on save causing bogus queries for "WHERE owner_id = NULL" even after owner was saved. 8713 [Bryan Helmkamp]
  • Refactor association create and build so before & after callbacks behave consistently. 8854 [Pratik Naik, mortent]
  • Quote table names. Defaults to column quoting. 4593 [Justin Lynn, gwcoffey, eadz, Dmitry V. Sabanin, Jeremy Kemper]
  • Alias association build to new so it behaves predictably. 8787 [Pratik Naik]
  • Add notes to documentation regarding attr_readonly behavior with counter caches and polymorphic associations. Closes 9835 [saimonmoore, rick]
  • Observers can observe model names as symbols properly now. Closes 9869 [queso]
  • find_and_(initialize|create)_by methods can now properly initialize protected attributes [Tobias Luetke]
  • belongs_to infers the foreign key from the association name instead of from the class name. [Jeremy Kemper]
  • PostgreSQL: support multiline default values. 7533 [Carl Lerche, aguynamedryan, Rein Henrichs, Tarmo Tänav]
  • MySQL: fix change_column on not-null columns that don‘t accept dfeault values of ’’. 6663 [Jonathan Viney, Tarmo Tänav]
  • validates_uniqueness_of behaves well with abstract superclasses and

single-table inheritance. 3833, 9886 [Gabriel Gironda, rramdas, François Beausoleil, Josh Peek, Tarmo Tänav, pat]

  • Warn about protected attribute assigments in development and test environments when mass-assigning to an attr_protected attribute. 9802 [Henrik N]
  • Speedup database date/time parsing. [Jeremy Kemper, Tarmo Tänav]
  • Fix calling .clear on a has_many :dependent=>:delete_all association. [Tarmo Tänav]
  • Allow change_column to set NOT NULL in the PostgreSQL adapter [Tarmo Tänav]
  • Fix that ActiveRecord would create attribute methods and override custom attribute getters if the method is also defined in Kernel.methods. [Rick]
  • Don‘t call attr_readonly on polymorphic belongs_to associations, in case it matches the name of some other non-ActiveRecord class/module. [Rick]
  • Try loading activerecord-<adaptername>-adapter gem before trying a plain require so you can use custom gems for the bundled adapters. Also stops gems from requiring an adapter from an old Active Record gem. [Jeremy Kemper, Derrick Spell]

*2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.14.2 - 1.15.3]

  • Add attr_readonly to specify columns that are skipped during a normal ActiveRecord save operation. Closes 6896 [dcmanges]

    class Comment < ActiveRecord::Base

      # Automatically sets Article#comments_count as readonly.
  belongs_to :article, :counter_cache => :comments_count

    end

    class Article < ActiveRecord::Base

      attr_readonly :approved_comments_count

    end

  • Make size for has_many :through use counter cache if it exists. Closes 9734 [xaviershay]
  • Remove DB2 adapter since IBM chooses to maintain their own adapter instead. [Jeremy Kemper]
  • Extract Oracle, SQLServer, and Sybase adapters into gems. [Jeremy Kemper]
  • Added fixture caching that‘ll speed up a normal fixture-powered test suite between 50% and 100% 9682 [Frederick Cheung]
  • Correctly quote id list for limited eager loading. 7482 [tmacedo]
  • Fixed that using version-targetted migrates would fail on loggers other than the default one 7430 [valeksenko]
  • Fixed rename_column for SQLite when using symbols for the column names 8616 [drodriguez]
  • Added the possibility of using symbols in addition to concrete classes with ActiveRecord::Observer#observe. 3998 [Robby Russell, Tarmo Tänav]
  • Added ActiveRecord::Base#to_json/from_json [DHH, Cheah Chu Yeow]
  • Added ActiveRecord::Base#from_xml [DHH]. Example:
      xml = "<person><name>David</name></person>"
  Person.new.from_xml(xml).name # => "David"
  • Define dynamic finders as real methods after first usage. [bscofield]
  • Deprecation: remove deprecated threaded_connections methods. Use allow_concurrency instead. [Jeremy Kemper]
  • Associations macros accept extension blocks alongside modules. 9346 [Josh Peek]
  • Speed up and simplify query caching. [Jeremy Kemper]
  • connection.select_rows ‘sql’ returns an array (rows) of arrays (field values). 2329 [Michael Schuerig]
  • Eager loading respects explicit :joins. 9496 [dasil003]
  • Extract Firebird, FrontBase, and OpenBase adapters into gems. 9508, 9509, 9510 [Jeremy Kemper]
  • RubyGem database adapters: expects a gem named activerecord-<database>-adapter with active_record/connection_adapters/<database>_adapter.rb in its load path. [Jeremy Kemper]
  • Fixed that altering join tables in migrations would fail w/ sqlite3 7453 [TimoMihaljov/brandon]
  • Fix association writer with :dependent => :nullify. 7314 [Jonathan Viney]
  • OpenBase: update for new lib and latest Rails. Support migrations. 8748 [dcsesq]
  • Moved acts_as_tree into a plugin of the same name on the official Rails svn. 9514 [Pratik Naik]
  • Moved acts_as_nested_set into a plugin of the same name on the official Rails svn. 9516 [Josh Peek]
  • Moved acts_as_list into a plugin of the same name on the official Rails svn. [Josh Peek]
  • Explicitly require active_record/query_cache before using it. [Jeremy Kemper]
  • Fix bug where unserializing an attribute attempts to modify a frozen @attributes hash for a deleted record. [Rick, marclove]
  • Performance: absorb instantiate and initialize_with_callbacks into the Base methods. [Jeremy Kemper]
  • Fixed that eager loading queries and with_scope should respect the :group option [DHH]
  • Improve performance and functionality of the postgresql adapter. Closes 8049 [roderickvd]
          For more information see: http://dev.rubyonrails.org/ticket/8049
  • Don‘t clobber includes passed to has_many.count [danger]
  • Make sure has_many uses :include when counting [danger]
  • Change the implementation of ActiveRecord‘s attribute reader and writer methods [nzkoz]
 - Generate Reader and Writer methods which cache attribute values in hashes.  This is to avoid repeatedly parsing the same date or integer columns.
 - Change exception raised when users use find with :select then try to access a skipped column.  Plugins could override missing_attribute() to lazily load the columns.
 - Move method definition to the class, instead of the instance
 - Always generate the readers, writers and predicate methods.
  • Perform a deep dup on query cache results so that modifying activerecord attributes does not modify the cached attributes. [Rick]

# Ensure that has_many :through associations use a count query instead of loading the target when size is called. Closes 8800 [Pratik Naik]

  • Added :unless clause to validations 8003 [monki]. Example:
      def using_open_id?
    !identity_url.blank?
  end

  validates_presence_of :identity_url, :if => using_open_id?
  validates_presence_of :username, :unless => using_open_id?
  validates_presence_of :password, :unless => using_open_id?
  • Fix count on a has_many :through association so that it recognizes the :uniq option. Closes 8801 [Pratik Naik]
  • Fix and properly document/test count(column_name) usage. Closes 8999 [Pratik Naik]
  • Remove deprecated count(conditions=nil, joins=nil) usage. Closes 8993 [Pratik Naik]
  • Change belongs_to so that the foreign_key assumption is taken from the association name, not the class name. Closes 8992 [hasmanyjosh]

    OLD

      belongs_to :visitor, :class_name => 'User' # => inferred foreign_key is user_id

    NEW

      belongs_to :visitor, :class_name => 'User' # => inferred foreign_key is visitor_id
  • Remove spurious tests from deprecated_associations_test, most of these aren‘t deprecated, and are duplicated in associations_test. Closes 8987 [Pratik Naik]
  • Make create! on a has_many :through association return the association object. Not the collection. Closes 8786 [Pratik Naik]
  • Move from select * to select tablename.* to avoid clobbering IDs. Closes 8889 [dasil003]
  • Don‘t call unsupported methods on associated objects when using :include, :method with to_xml 7307, [manfred, jwilger]
  • Define collection singular ids method for has_many :through associations. 8763 [Pratik Naik]
  • Array attribute conditions work with proxied association collections. 8318 [Kamal Fariz Mahyuddin, theamazingrando]
  • Fix polymorphic has_one associations declared in an abstract class. 8638 [Pratik Naik, Dax Huiberts]
  • Fixed validates_associated should not stop on the first error. 4276 [mrj, Manfred Stienstra, Josh Peek]
  • Rollback if commit raises an exception. 8642 [kik, Jeremy Kemper]
  • Update tests’ use of fixtures for the new collections api. 8726 [Kamal Fariz Mahyuddin]
  • Save associated records only if the association is already loaded. 8713 [blaine]
  • MySQL: fix show_variable. 8448 [matt, Jeremy Kemper]
  • Fixtures: correctly delete and insert fixtures in a single transaction. 8553 [Michael Schuerig]
  • Fixtures: people(:technomancy, :josh) returns both fixtures. 7880 [technomancy, Josh Peek]
  • Calculations support non-numeric foreign keys. 8154 [Kamal Fariz Mahyuddin]
  • with_scope is protected. 8524 [Josh Peek]
  • Quickref for association methods. 7723 [marclove, Mindsweeper]
  • Calculations: return nil average instead of 0 when there are no rows to average. 8298 [davidw]
  • acts_as_nested_set: direct_children is sorted correctly. 4761 [Josh Peek, rails@33lc0.net]
  • Raise an exception if both attr_protected and attr_accessible are declared. 8507 [stellsmi]
  • SQLite, MySQL, PostgreSQL, Oracle: quote column names in column migration SQL statements. 8466 [marclove, lorenjohnson]
  • Allow nil serialized attributes with a set class constraint. 7293 [sandofsky]
  • Oracle: support binary fixtures. 7987 [Michael Schoen]
  • Fixtures: pull fixture insertion into the database adapters. 7987 [Michael Schoen]
  • Announce migration versions as they‘re performed. [Jeremy Kemper]
  • find gracefully copes with blank :conditions. 7599 [Dan Manges, johnnyb]
  • validates_numericality_of takes :greater_than, :greater_than_or_equal_to, :equal_to, :less_than, :less_than_or_equal_to, :odd, and :even options. 3952 [Bob Silva, Dan Kubb, Josh Peek]
  • MySQL: create_database takes :charset and :collation options. Charset defaults to utf8. 8448 [matt]
  • Find with a list of ids supports limit/offset. 8437 [hrudududu]
  • Optimistic locking: revert the lock version when an update fails. 7840 [plang]
  • Migrations: add_column supports custom column types. 7742 [jsgarvin, Theory]
  • Load database adapters on demand. Eliminates config.connection_adapters and RAILS_CONNECTION_ADAPTERS. Add your lib directory to the $LOAD_PATH and put your custom adapter in lib/active_record/connection_adapters/adaptername_adapter.rb. This way you can provide custom adapters as plugins or gems without modifying Rails. [Jeremy Kemper]
  • Ensure that associations with :dependent => :delete_all respect :conditions option. Closes 8034 [danger, Josh Peek, Rick]
  • belongs_to assignment creates a new proxy rather than modifying its target in-place. 8412 [mmangino@elevatedrails.com]
  • Fix column type detection while loading fixtures. Closes 7987 [roderickvd]
  • Document deep eager includes. 6267 [Josh Susser, Dan Manges]
  • Document warning that associations names shouldn‘t be reserved words. 4378 [murphy@cYcnus.de, Josh Susser]
  • Sanitize Base#inspect. 8392, 8623 [Nik Wakelin, jnoon]
  • Replace the transaction {|transaction|..} semantics with a new Exception ActiveRecord::Rollback. [Koz]
  • Oracle: extract column length for CHAR also. 7866 [ymendel]
  • Document :allow_nil option for validates_acceptance_of since it defaults to true. [tzaharia]
  • Update documentation for :dependent declaration so that it explicitly uses the non-deprecated API. [danger]
  • Add documentation caveat about when to use count_by_sql. [fearoffish]
  • Enhance documentation for increment_counter and decrement_counter. [fearoffish]
  • Provide brief introduction to what optimistic locking is. [fearoffish]
  • Add documentation for :encoding option to mysql adapter. [marclove]
  • Added short-hand declaration style to migrations (inspiration from Sexy Migrations, errtheblog.com/post/2381) [DHH]. Example:
      create_table "products" do |t|
    t.column "shop_id",    :integer
    t.column "creator_id", :integer
    t.column "name",       :string,   :default => "Untitled"
    t.column "value",      :string,   :default => "Untitled"
    t.column "created_at", :datetime
    t.column "updated_at", :datetime
  end

    …can now be written as:

      create_table :products do |t|
    t.integer :shop_id, :creator_id
    t.string  :name, :value, :default => "Untitled"
    t.timestamps
  end
  • Use association name for the wrapper element when using .to_xml. Previous behavior lead to non-deterministic situations with STI and polymorphic associations. [Koz, jstrachan]
  • Improve performance of calling .create on has_many :through associations. [evan]
  • Improved cloning performance by relying less on exception raising 8159 [Blaine]
  • Added ActiveRecord::Base.inspect to return a column-view like #<Post id:integer, title:string, body:text> [DHH]
  • Added yielding of Builder instance for ActiveRecord::Base#to_xml calls [DHH]
  • Small additions and fixes for ActiveRecord documentation. Closes 7342 [jeremymcanally]
  • Add helpful debugging info to the ActiveRecord::StatementInvalid exception in ActiveRecord::ConnectionAdapters::SqliteAdapter#table_structure. Closes 7925. [court3nay]
  • SQLite: binary escaping works with $KCODE=’u’. 7862 [tsuka]
  • Base#to_xml supports serialized attributes. 7502 [jonathan]
  • Base.update_all :order and :limit options. Useful for MySQL updates that must be ordered to avoid violating unique constraints. [Jeremy Kemper]
  • Remove deprecated object transactions. People relying on this functionality should install the object_transactions plugin at code.bitsweat.net/svn/object_transactions. Closes 5637 [Koz, Jeremy Kemper]
  • PostgreSQL: remove DateTime -> Time downcast. Warning: do not enable translate_results for the C bindings if you have timestamps outside Time‘s domain. [Jeremy Kemper]
  • find_or_create_by_* takes a hash so you can create with more attributes than are in the method name. For example, Person.find_or_create_by_name(:name => ‘Henry’, :comments => ‘Hi new user!’) is equivalent to Person.find_by_name(‘Henry’) || Person.create(:name => ‘Henry’, :comments => ‘Hi new user!’). 7368 [Josh Susser]
  • Make sure with_scope takes both :select and :joins into account when setting :readonly. Allows you to save records you retrieve using method_missing on a has_many :through associations. [Koz]
  • Allow a polymorphic :source for has_many :through associations. Closes 7143 [protocool]
  • Consistent public/protected/private visibility for chained methods. 7813 [Dan Manges]
  • Oracle: fix quoted primary keys and datetime overflow. 7798 [Michael Schoen]
  • Consistently quote primary key column names. 7763 [toolmantim]
  • Fixtures: fix YAML ordered map support. 2665 [Manuel Holtgrewe, nfbuckley]
  • DateTimes assume the default timezone. 7764 [Geoff Buesing]
  • Sybase: hide timestamp columns since they‘re inherently read-only. 7716 [Mike Joyce]
  • Oracle: overflow Time to DateTime. 7718 [Michael Schoen]
  • PostgreSQL: don‘t use async_exec and async_query with postgres-pr. 7727, 7762 [flowdelic, toolmantim]
  • Fix has_many :through << with custom foreign keys. 6466, 7153 [naffis, Rich Collins]
  • Test DateTime native type in migrations, including an edge case with dates

during calendar reform. 7649, 7724 [fedot, Geoff Buesing]

  • SQLServer: correctly schema-dump tables with no indexes or descending indexes. 7333, 7703 [Jakob S, Tom Ward]
  • SQLServer: recognize real column type as Ruby float. 7057 [sethladd, Tom Ward]
  • Added fixtures :all as a way of loading all fixtures in the fixture directory at once 7214 [manfred]
  • Added database connection as a yield parameter to ActiveRecord::Base.transaction so you can manually rollback [DHH]. Example:
      transaction do |transaction|
    david.withdrawal(100)
    mary.deposit(100)
    transaction.rollback! # rolls back the transaction that was otherwise going to be successful
  end
  • Made increment_counter/decrement_counter play nicely with optimistic locking, and added a more general update_counters method [Jamis Buck]
  • Reworked David‘s query cache to be available as Model.cache {…}. For the duration of the block no select query should be run more then once. Any inserts/deletes/executes will flush the whole cache however [Tobias Luetke] Task.cache { Task.find(1); Task.find(1) } #=> 1 query
  • When dealing with SQLite3, use the table_info pragma helper, so that the bindings can do some translation for when sqlite3 breaks incompatibly between point releases. [Jamis Buck]
  • Oracle: fix lob and text default handling. 7344 [gfriedrich, Michael Schoen]
  • SQLServer: don‘t choke on strings containing ‘null’. 7083 [Jakob S]
  • MySQL: blob and text columns may not have defaults in 5.x. Update fixtures schema for strict mode. 6695 [Dan Kubb]
  • update_all can take a Hash argument. sanitize_sql splits into two methods for conditions and assignment since NULL values and delimiters are handled differently. 6583, 7365 [sandofsky, Assaf]
  • MySQL: SET SQL_AUTO_IS_NULL=0 so ‘where id is null’ doesn‘t select the last inserted id. 6778 [Jonathan Viney, timc]
  • Use Date#to_s(:db) for quoted dates. 7411 [Michael Schoen]
  • Don‘t create instance writer methods for class attributes. Closes 7401 [Rick]
  • Docs: validations examples. 7343 [zackchandler]
  • Add missing tests ensuring callbacks work with class inheritance. Closes 7339 [sandofsky]
  • Fixtures use the table name and connection from set_fixture_class. 7330 [Anthony Eden]
  • Remove useless code in attribute_present? since 0 != blank?. Closes 7249 [Josh Susser]
  • Fix minor doc typos. Closes 7157 [Josh Susser]
  • Fix incorrect usage of classify when creating the eager loading join statement. Closes 7044 [Josh Susser]
  • SQLServer: quote table name in indexes query. 2928 [keithm@infused.org]
  • Subclasses of an abstract class work with single-table inheritance. 5704, 7284 [BertG, nick+rails@ag.arizona.edu]
  • Make sure sqlite3 driver closes open connections on disconnect [Rob Rasmussen]
  • [DOC] clear up some ambiguity with the way has_and_belongs_to_many creates the default join table name. 7072 [jeremymcanally]
  • change_column accepts :default => nil. Skip column options for primary keys. 6956, 7048 [Dan Manges, Jeremy Kemper]
  • MySQL, PostgreSQL: change_column_default quotes the default value and doesn‘t lose column type information. 3987, 6664 [Jonathan Viney, manfred, altano@bigfoot.com]
  • Oracle: create_table takes a :sequence_name option to override the ‘tablename_seq’ default. 7000 [Michael Schoen]
  • MySQL: retain SSL settings on reconnect. 6976 [randyv2]
  • Apply scoping during initialize instead of create. Fixes setting of foreign key when using find_or_initialize_by with scoping. [Cody Fauser]
  • SQLServer: handle [quoted] table names. 6635 [rrich]
  • acts_as_nested_set works with single-table inheritance. 6030 [Josh Susser]
  • PostgreSQL, Oracle: correctly perform eager finds with :limit and :order. 4668, 7021 [eventualbuddha, Michael Schoen]
  • Pass a range in :conditions to use the SQL BETWEEN operator. 6974 [Dan Manges]
      Student.find(:all, :conditions => { :grade => 9..12 })
  • Fix the Oracle adapter for serialized attributes stored in CLOBs. Closes 6825 [mschoen, tdfowler]
  • [DOCS] Apply more documentation for ActiveRecord Reflection. Closes 4055 [Robby Russell]
  • [DOCS] Document :allow_nil option of validate_uniqueness_of. Closes 3143 [Caio Chassot]
  • Bring the sybase adapter up to scratch for 1.2 release. [jsheets]
  • Rollback new_record? and id when an exception is raised in a save callback. 6910 [Ben Curren, outerim]
  • Pushing a record on an association collection doesn‘t unnecessarily load all the associated records. [Obie Fernandez, Jeremy Kemper]
  • Oracle: fix connection reset failure. 6846 [leonlleslie]
  • Subclass instantiation doesn‘t try to explicitly require the corresponding subclass. 6840 [leei, Jeremy Kemper]
  • fix faulty inheritance tests and that eager loading grabs the wrong inheritance column when the class of your association is an STI subclass. Closes 6859 [protocool]
  • Consolidated different create and create! versions to call through to the base class with scope. This fixes inconsistencies, especially related to protected attribtues. Closes 5847 [Alexander Dymo, Tobias Luetke]
  • find supports :lock with :include. Check whether your database allows SELECT … FOR UPDATE with outer joins before using. 6764 [vitaly, Jeremy Kemper]
  • Add AssociationCollection#create! to be consistent with AssociationCollection#create when dealing with a foreign key that is a protected attribute [Cody Fauser]
  • Added counter optimization for AssociationCollection#any? so person.friends.any? won‘t actually load the full association if we have the count in a cheaper form [DHH]
  • Change fixture_path to a class inheritable accessor allowing test cases to have their own custom set of fixtures. 6672 [zdennis]
  • Quote ActiveSupport::Multibyte::Chars. 6653 [Julian Tarkhanov]
  • Simplify query_attribute by typecasting the attribute value and checking whether it‘s nil, false, zero or blank. 6659 [Jonathan Viney]
  • validates_numericality_of uses \A \Z to ensure the entire string matches rather than ^ $ which may match one valid line of a multiline string. 5716 [Andreas Schwarz]
  • Run validations in the order they were declared. 6657 [obrie]
  • MySQL: detect when a NOT NULL column without a default value is misreported as default ’’. Can‘t detect for string, text, and binary columns since ’’ is a legitimate default. 6156 [simon@redhillconsulting.com.au, obrie, Jonathan Viney, Jeremy Kemper]
  • Simplify association proxy implementation by factoring construct_scope out of method_missing. 6643 [martin]
  • Oracle: automatically detect the primary key. 6594 [vesaria, Michael Schoen]
  • Oracle: to increase performance, prefetch 100 rows and enable similar cursor sharing. Both are configurable in database.yml. 6607 [philbogle@gmail.com, ray.fortna@jobster.com, Michael Schoen]
  • Don‘t inspect unloaded associations. 2905 [lmarlow]
  • SQLite: use AUTOINCREMENT primary key in >= 3.1.0. 6588, 6616 [careo, lukfugl]
  • Cache inheritance_column. 6592 [Stefan Kaes]
  • Firebird: decimal/numeric support. 6408 [macrnic]
  • make add_order a tad faster. 6567 [Stefan Kaes]
  • Find with :include respects scoped :order. 5850
  • Support nil and Array in :conditions => { attr => value } hashes. 6548 [Assaf, Jeremy Kemper]
      find(:all, :conditions => { :topic_id => [1, 2, 3], :last_read => nil }
  • Consistently use LOWER() for uniqueness validations (rather than mixing with UPPER()) so the database can always use a functional index on the lowercased column. 6495 [Si]
  • SQLite: fix calculations workaround, remove count(distinct) query rewrite, cleanup test connection scripts. [Jeremy Kemper]
  • SQLite: count(distinct) queries supported in >= 3.2.6. 6544 [Bob Silva]
  • Dynamically generate reader methods for serialized attributes. 6362 [Stefan Kaes]
  • Deprecation: object transactions warning. [Jeremy Kemper]
  • has_one :dependent => :nullify ignores nil associates. 4848, 6528 [bellis@deepthought.org, janovetz, Jeremy Kemper]
  • Oracle: resolve test failures, use prefetched primary key for inserts, check for null defaults, fix limited id selection for eager loading. Factor out some common methods from all adapters. 6515 [Michael Schoen]
  • Make add_column use the options hash with the Sqlite Adapter. Closes 6464 [obrie]
  • Document other options available to migration‘s add_column. 6419 [grg]
  • MySQL: all_hashes compatibility with old MysqlRes class. 6429, 6601 [Jeremy Kemper]
  • Fix has_many :through to add the appropriate conditions when going through an association using STI. Closes 5783. [Jonathan Viney]
  • fix select_limited_ids_list issues in postgresql, retain current behavior in other adapters [Rick]
  • Restore eager condition interpolation, document it‘s differences [Rick]
  • Don‘t rollback in teardown unless a transaction was started. Don‘t start a transaction in create_fixtures if a transaction is started. 6282 [Jacob Fugal, Jeremy Kemper]
  • Add delete support to has_many :through associations. Closes 6049 [Martin Landers]
  • Reverted old select_limited_ids_list postgresql fix that caused issues in mysql. Closes 5851 [Rick]
  • Removes the ability for eager loaded conditions to be interpolated, since there is no model instance to use as a context for interpolation. 5553 [turnip@turnipspatch.com]
  • Added timeout option to SQLite3 configurations to deal more gracefully with SQLite3::BusyException, now the connection can instead retry for x seconds to see if the db clears up before throwing that exception 6126 [wreese@gmail.com]
  • Added update_attributes! which uses save! to raise an exception if a validation error prevents saving 6192 [jonathan]
  • Deprecated add_on_boundary_breaking (use validates_length_of instead) 6292 [BobSilva]
  • The has_many create method works with polymorphic associations. 6361 [Dan Peterson]
  • MySQL: introduce Mysql::Result#all_hashes to support further optimization. 5581 [Stefan Kaes]
  • save! shouldn‘t validate twice. 6324 [maiha, Bob Silva]
  • Association collections have an _ids reader method to match the existing writer for collection_select convenience (e.g. employee.task_ids). The writer method skips blank ids so you can safely do @employee.task_ids = params[:tasks] without checking every time for an empty list or blank values. 1887, 5780 [Michael Schuerig]
  • Add an attribute reader method for ActiveRecord::Base.observers [Rick Olson]
  • Deprecation: count class method should be called with an options hash rather than two args for conditions and joins. 6287 [Bob Silva]
  • has_one associations with a nil target may be safely marshaled. 6279 [norbauer, Jeremy Kemper]
  • Duplicate the hash provided to AR::Base#to_xml to prevent unexpected side effects [Koz]
  • Add a :namespace option to AR::Base#to_xml [Koz]
  • Deprecation tests. Remove warnings for dynamic finders and for the foo_count method if it‘s also an attribute. [Jeremy Kemper]
  • Mock Time.now for more accurate Touch mixin tests. 6213 [Dan Peterson]
  • Improve yaml fixtures error reporting. 6205 [Bruce Williams]
  • Rename AR::Base#quote so people can use that name in their models. 3628 [Koz]
  • Add deprecation warning for inferred foreign key. 6029 [Josh Susser]
  • Fixed the Ruby/MySQL adapter we ship with Active Record to work with the new authentication handshake that was introduced in MySQL 4.1, along with the other protocol changes made at that time 5723 [jimw@mysql.com]
  • Deprecation: use :dependent => :delete_all rather than :exclusively_dependent => true. 6024 [Josh Susser]
  • Document validates_presences_of behavior with booleans: you probably want validates_inclusion_of :attr, :in => [true, false]. 2253 [Bob Silva]
  • Optimistic locking: gracefully handle nil versions, treat as zero. 5908 [Tom Ward]
  • to_xml: the :methods option works on arrays of records. 5845 [Josh Starcher]
  • Deprecation: update docs. 5998 [jakob@mentalized.net, Kevin Clark]
  • Add some XmlSerialization tests for ActiveRecord [Rick Olson]
  • has_many :through conditions are sanitized by the associating class. 5971 [martin.emde@gmail.com]
  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Fix spurious newlines and spaces in AR::Base#to_xml output [Jamis Buck]
  • has_one supports the :dependent => :delete option which skips the typical callback chain and deletes the associated object directly from the database. 5927 [Chris Mear, Jonathan Viney]
  • Nested subclasses are not prefixed with the parent class’ table_name since they should always use the base class’ table_name. 5911 [Jonathan Viney]
  • SQLServer: work around bug where some unambiguous date formats are not correctly identified if the session language is set to german. 5894 [Tom Ward, kruth@bfpi]
  • SQLServer: fix eager association test. 5901 [Tom Ward]
  • Clashing type columns due to a sloppy join shouldn‘t wreck single-table inheritance. 5838 [Kevin Clark]
  • Fixtures: correct escaping of \n and \r. 5859 [evgeny.zislis@gmail.com]
  • Migrations: gracefully handle missing migration files. 5857 [eli.gordon@gmail.com]
  • MySQL: update test schema for MySQL 5 strict mode. 5861 [Tom Ward]
  • to_xml: correct naming of included associations. 5831 [josh.starcher@gmail.com]
  • Pushing a record onto a has_many :through sets the association‘s foreign key to the associate‘s primary key and adds it to the correct association. 5815, 5829 [josh@hasmanythrough.com]
  • Add records to has_many :through using <<, push, and concat by creating the association record. Raise if base or associate are new records since both ids are required to create the association. build raises since you can‘t associate an unsaved record. create! takes an attributes hash and creates the associated record and its association in a transaction. [Jeremy Kemper]
      # Create a tagging to associate the post and tag.
  post.tags << Tag.find_by_name('old')
  post.tags.create! :name => 'general'

  # Would have been:
  post.taggings.create!(:tag => Tag.find_by_name('finally')
  transaction do
    post.taggings.create!(:tag => Tag.create!(:name => 'general'))
  end
  • Cache nil results for :included has_one associations also. 5787 [Michael Schoen]
  • Fixed a bug which would cause .save to fail after trying to access a empty has_one association on a unsaved record. [Tobias Luetke]
  • Nested classes are given table names prefixed by the singular form of the parent‘s table name. [Jeremy Kemper]
      Example: Invoice::Lineitem is given table name invoice_lineitems
  • Migrations: uniquely name multicolumn indexes so you don‘t have to. [Jeremy Kemper]
      # people_active_last_name_index, people_active_deactivated_at_index
  add_index    :people, [:active, :last_name]
  add_index    :people, [:active, :deactivated_at]
  remove_index :people, [:active, :last_name]
  remove_index :people, [:active, :deactivated_at]

    WARNING: backward-incompatibility. Multicolumn indexes created before this revision were named using the first column name only. Now they‘re uniquely named using all indexed columns.

    To remove an old multicolumn index, remove_index :table_name, :first_column

  • Fix for deep includes on the same association. [richcollins@gmail.com]
  • Tweak fixtures so they don‘t try to use a non-ActiveRecord class. [Kevin Clark]
  • Remove ActiveRecord::Base.reset since Dispatcher doesn‘t use it anymore. [Rick Olson]
  • Document find‘s :from option. Closes 5762. [andrew@redlinesoftware.com]
  • PostgreSQL: autodetected sequences work correctly with multiple schemas. Rely on the schema search_path instead of explicitly qualifying the sequence name with its schema. 5280 [guy.naor@famundo.com]
  • Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
  • Cache nil results for has_one associations so multiple calls don‘t call the database. Closes 5757. [Michael A. Schoen]
  • Add documentation for how to disable timestamps on a per model basis. Closes 5684. [matt@mattmargolis.net Marcel Molina Jr.]
  • Don‘t save has_one associations unnecessarily. 5735 [Jonathan Viney]
  • Refactor ActiveRecord::Base.reset_subclasses to reset, and add global observer resetting. [Rick Olson]
  • Formally deprecate the deprecated finders. [Koz]
  • Formally deprecate rich associations. [Koz]
  • Fixed that default timezones for new / initialize should uphold utc setting 5709 [daniluk@yahoo.com]
  • Fix announcement of very long migration names. 5722 [blake@near-time.com]
  • The exists? class method should treat a string argument as an id rather than as conditions. 5698 [jeremy@planetargon.com]
  • Fixed to_xml with :include misbehaviors when invoked on array of model instances 5690 [alexkwolfe@gmail.com]
  • Added support for conditions on Base.exists? 5689 [Josh Peek]. Examples:
      assert (Topic.exists?(:author_name => "David"))
        assert (Topic.exists?(:author_name => "Mary", :approved => true))
        assert (Topic.exists?(["parent_id = ?", 1]))
  • Schema dumper quotes date :default values. [Dave Thomas]
  • Calculate sum with SQL, not Enumerable on HasManyThrough Associations. [Dan Peterson]
  • Factor the attribute#{suffix} methods out of method_missing for easier extension. [Jeremy Kemper]
  • Patch sql injection vulnerability when using integer or float columns. [Jamis Buck]
  • Allow count through a has_many association to accept :include. [Dan Peterson]
  • create_table rdoc: suggest :id => false for habtm join tables. [Zed Shaw]
  • PostgreSQL: return array fields as strings. 4664 [Robby Russell]
  • SQLServer: added tests to ensure all database statements are closed, refactored identity_insert management code to use blocks, removed update/delete rowcount code out of execute and into update/delete, changed insert to go through execute method, removed unused quoting methods, disabled pessimistic locking tests as feature is currently unsupported, fixed RakeFile to load sqlserver specific tests whether running in ado or odbc mode, fixed support for recently added decimal types, added support for limits on integer types. 5670 [Tom Ward]
  • SQLServer: fix db:schema:dump case-sensitivity. 4684 [Will Rogers]
  • Oracle: BigDecimal support. 5667 [schoenm@earthlink.net]
  • Numeric and decimal columns map to BigDecimal instead of Float. Those with scale 0 map to Integer. 5454 [robbat2@gentoo.org, work@ashleymoran.me.uk]
  • Firebird migrations support. 5337 [Ken Kunz <kennethkunz@gmail.com>]
  • PostgreSQL: create/drop as postgres user. 4790 [mail@matthewpainter.co.uk, mlaster@metavillage.com]
  • Update callbacks documentation. 3970 [Robby Russell <robby@planetargon.com>]
  • PostgreSQL: correctly quote the ’ in pk_and_sequence_for. 5462 [tietew@tietew.net]
  • PostgreSQL: correctly quote microseconds in timestamps. 5641 [rick@rickbradley.com]
  • Clearer has_one/belongs_to model names (account has_one :user). 5632 [matt@mattmargolis.net]
  • Oracle: use nonblocking queries if allow_concurrency is set, fix pessimistic locking, don‘t guess date vs. time by default (set OracleAdapter.emulate_dates = true for the old behavior), adapter cleanup. 5635 [schoenm@earthlink.net]
  • Fixed a few Oracle issues: Allows Oracle‘s odd date handling to still work consistently within to_xml, Passes test that hardcode insert statement by dropping the :id column, Updated RUNNING_UNIT_TESTS with Oracle instructions, Corrects method signature for exec 5294 [schoenm@earthlink.net]
  • Added :group to available options for finds done on associations 5516 [mike@michaeldewey.org]
  • Minor tweak to improve performance of ActiveRecord::Base#to_param.
  • Observers also watch subclasses created after they are declared. 5535 [daniels@pronto.com.au]
  • Removed deprecated timestamps_gmt class methods. [Jeremy Kemper]
  • rake build_mysql_database grants permissions to rails@localhost. 5501 [brianegge@yahoo.com]
  • PostgreSQL: support microsecond time resolution. 5492 [alex@msgpad.com]
  • Add AssociationCollection#sum since the method_missing invokation has been shadowed by Enumerable#sum.
  • Added find_or_initialize_by_X which works like find_or_create_by_X but doesn‘t save the newly instantiated record. [Sam Stephenson]
  • Row locking. Provide a locking clause with the :lock finder option or true for the default "FOR UPDATE". Use the lock! method to obtain a row lock on a single record (reloads the record with :lock => true). [Shugo Maeda]
      # Obtain an exclusive lock on person 1 so we can safely increment visits.
  Person.transaction do
    # select * from people where id=1 for update
    person = Person.find(1, :lock => true)
    person.visits += 1
    person.save!
  end
  • PostgreSQL: introduce allow_concurrency option which determines whether to use blocking or asynchronous execute. Adapters with blocking execute will deadlock Ruby threads. The default value is ActiveRecord::Base.allow_concurrency. [Jeremy Kemper]
  • Use a per-thread (rather than global) transaction mutex so you may execute concurrent transactions on separate connections. [Jeremy Kemper]
  • Change AR::Base#to_param to return a String instead of a Fixnum. Closes 5320. [Nicholas Seckar]
  • Use explicit delegation instead of method aliasing for AR::Base.to_param -> AR::Base.id. 5299 (skaes@web.de)
  • Refactored ActiveRecord::Base.to_xml to become a delegate for XmlSerializer, which restores sanity to the mega method. This refactoring also reinstates the opinions that type="string" is redundant and ugly and nil-differentiation is not a concern of serialization [DHH]
  • Added simple hash conditions to find that‘ll just convert hash to an AND-based condition string 5143 [hcatlin@gmail.com]. Example:
      Person.find(:all, :conditions => { :last_name => "Catlin", :status => 1 }, :limit => 2)

…is the same as:

    Person.find(:all, :conditions => [ "last_name = ? and status = ?", "Catlin", 1 ], :limit => 2)

  This makes it easier to pass in the options from a form or otherwise outside.
  • Fixed issues with BLOB limits, charsets, and booleans for Firebird 5194, 5191, 5189 [kennethkunz@gmail.com]
  • Fixed usage of :limit and with_scope when the association in scope is a 1:m 5208 [alex@purefiction.net]
  • Fixed migration trouble with SQLite when NOT NULL is used in the new definition 5215 [greg@lapcominc.com]
  • Fixed problems with eager loading and counting on SQL Server 5212 [kajism@yahoo.com]
  • Fixed that count distinct should use the selected column even when using :include 5251 [anna@wota.jp]
  • Fixed that :includes merged from with_scope won‘t cause the same association to be loaded more than once if repetition occurs in the clauses 5253 [alex@purefiction.net]
  • Allow models to override to_xml. 4989 [Blair Zajac <blair@orcaware.com>]
  • PostgreSQL: don‘t ignore port when host is nil since it‘s often used to label the domain socket. 5247 [shimbo@is.naist.jp]
  • Records and arrays of records are bound as quoted ids. [Jeremy Kemper]
      Foo.find(:all, :conditions => ['bar_id IN (?)', bars])
  Foo.find(:first, :conditions => ['bar_id = ?', bar])
  • Fixed that Base.find :all, :conditions => [ "id IN (?)", collection ] would fail if collection was empty [DHH]
  • Add a list of regexes assert_queries skips in the ActiveRecord test suite. [Rick]
  • Fix the has_and_belongs_to_many create doesn‘t populate the join for new records. Closes 3692 [josh@hasmanythrough.com]
  • Provide Association Extensions access to the instance that the association is being accessed from. Closes 4433 [josh@hasmanythrough.com]
  • Update OpenBase adaterp‘s maintainer‘s email address. Closes 5176. [Derrick Spell]
  • Add a quick note about :select and eagerly included associations. [Rick]
  • Add docs for the :as option in has_one associations. Closes 5144 [cdcarter@gmail.com]
  • Fixed that has_many collections shouldn‘t load the entire association to do build or create [DHH]
  • Added :allow_nil option for aggregations 5091 [ian.w.white@gmail.com]
  • Fix Oracle boolean support and tests. Closes 5139. [schoenm@earthlink.net]
  • create! no longer blows up when no attributes are passed and a :create scope is in effect (e.g. foo.bars.create! failed whereas foo.bars.create!({}) didn‘t.) [Jeremy Kemper]
  • Call Inflector#demodulize on the class name when eagerly including an STI model. Closes 5077 [info@loobmedia.com]
  • Preserve MySQL boolean column defaults when changing a column in a migration. Closes 5015. [pdcawley@bofh.org.uk]
  • PostgreSQL: migrations support :limit with :integer columns by mapping limit < 4 to smallint, > 4 to bigint, and anything else to integer. 2900 [keegan@thebasement.org]
  • Dates and times interpret empty strings as nil rather than 2000-01-01. 4830 [kajism@yahoo.com]
  • Allow :uniq => true with has_many :through associations. [Jeremy Kemper]
  • Ensure that StringIO is always available for the Schema dumper. [Marcel Molina Jr.]
  • Allow AR::Base#to_xml to include methods too. Closes 4921. [johan@textdrive.com]
  • Replace superfluous name_to_class_name variant with camelize. [Marcel Molina Jr.]
  • Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Remove duplicate fixture entry in comments.yml. Closes 4923. [Blair Zajac <blair@orcaware.com>]
  • Update FrontBase adapter to check binding version. Closes 4920. [mlaster@metavillage.com]
  • New Frontbase connections don‘t start in auto-commit mode. Closes 4922. [mlaster@metavillage.com]
  • When grouping, use the appropriate option key. [Marcel Molina Jr.]
  • Only modify the sequence name in the FrontBase adapter if the FrontBase adapter is actually being used. [Marcel Molina Jr.]
  • Add support for FrontBase (www.frontbase.com/) with a new adapter thanks to the hard work of one Mike Laster. Closes 4093. [mlaster@metavillage.com]
  • Add warning about the proper way to validate the presence of a foreign key. Closes 4147. [Francois Beausoleil <francois.beausoleil@gmail.com>]
  • Fix syntax error in documentation. Closes 4679. [mislav@nippur.irb.hr]
  • Add Oracle support for CLOB inserts. Closes 4748. [schoenm@earthlink.net sandra.metz@duke.edu]
  • Various fixes for sqlserver_adapter (odbc statement finishing, ado schema dumper, drop index). Closes 4831. [kajism@yahoo.com]
  • Add support for :order option to with_scope. Closes 3887. [eric.daspet@survol.net]
  • Prettify output of schema_dumper by making things line up. Closes 4241 [Caio Chassot <caio@v2studio.com>]
  • Make build_postgresql_databases task make databases owned by the postgres user. Closes 4790. [mlaster@metavillage.com]
  • Sybase Adapter type conversion cleanup. Closes 4736. [dev@metacasa.net]
  • Fix bug where calculations with long alias names return null. [Rick]
  • Raise error when trying to add to a has_many :through association. Use the Join Model instead. [Rick]
      @post.tags << @tag                  # BAD
  @post.taggings.create(:tag => @tag) # GOOD
  • Allow all calculations to take the :include option, not just COUNT (closes 4840) [Rick]
  • Update inconsistent migrations documentation. 4683 [machomagna@gmail.com]
  • Add ActiveRecord::Errors#to_xml [Jamis Buck]
  • Properly quote index names in migrations (closes 4764) [John Long]
  • Fix the HasManyAssociation#count method so it uses the new ActiveRecord::Base#count syntax, while maintaining backwards compatibility. [Rick]
  • 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]
  • DRY up association collection reader method generation. [Marcel Molina Jr.]
  • DRY up and tweak style of the validation error object. [Marcel Molina Jr.]
  • Add :case_sensitive option to validates_uniqueness_of (closes 3090) [Rick]
      class Account < ActiveRecord::Base
    validates_uniqueness_of :email, :case_sensitive => false
  end
  • Allow multiple association extensions with :extend option (closes 4666) [Josh Susser]
      class Account < ActiveRecord::Base
    has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
  end

  *1.15.3* (March 12th, 2007)

  * Allow a polymorphic :source for has_many :through associations. Closes #7143 [protocool]

  * Consistently quote primary key column names.  #7763 [toolmantim]

  * Fixtures: fix YAML ordered map support.  #2665 [Manuel Holtgrewe, nfbuckley]

  * Fix has_many :through << with custom foreign keys.  #6466, #7153 [naffis, Rich Collins]

*1.15.2* (February 5th, 2007)

  • Pass a range in :conditions to use the SQL BETWEEN operator. 6974 [dcmanges]
      Student.find(:all, :conditions => { :grade => 9..12 })
  • Don‘t create instance writer methods for class attributes. [Rick]
  • When dealing with SQLite3, use the table_info pragma helper, so that the bindings can do some translation for when sqlite3 breaks incompatibly between point releases. [Jamis Buck]
  • SQLServer: don‘t choke on strings containing ‘null’. 7083 [Jakob S]
  • Consistently use LOWER() for uniqueness validations (rather than mixing with UPPER()) so the database can always use a functional index on the lowercased column. 6495 [Si]
  • MySQL: SET SQL_AUTO_IS_NULL=0 so ‘where id is null’ doesn‘t select the last inserted id. 6778 [Jonathan Viney, timc]
  • Fixtures use the table name and connection from set_fixture_class. 7330 [Anthony Eden]
  • SQLServer: quote table name in indexes query. 2928 [keithm@infused.org]

*1.15.1* (January 17th, 2007)

  • Fix nodoc breaking of adapters

*1.15.0* (January 16th, 2007)

  • [DOC] clear up some ambiguity with the way has_and_belongs_to_many creates the default join table name. 7072 [jeremymcanally]
  • change_column accepts :default => nil. Skip column options for primary keys. 6956, 7048 [dcmanges, Jeremy Kemper]
  • MySQL, PostgreSQL: change_column_default quotes the default value and doesn‘t lose column type information. 3987, 6664 [Jonathan Viney, manfred, altano@bigfoot.com]
  • Oracle: create_table takes a :sequence_name option to override the ‘tablename_seq’ default. 7000 [Michael Schoen]
  • MySQL: retain SSL settings on reconnect. 6976 [randyv2]
  • SQLServer: handle [quoted] table names. 6635 [rrich]
  • acts_as_nested_set works with single-table inheritance. 6030 [Josh Susser]
  • PostgreSQL, Oracle: correctly perform eager finds with :limit and :order. 4668, 7021 [eventualbuddha, Michael Schoen]
  • Fix the Oracle adapter for serialized attributes stored in CLOBs. Closes 6825 [mschoen, tdfowler]
  • [DOCS] Apply more documentation for ActiveRecord Reflection. Closes 4055 [Robby Russell]
  • [DOCS] Document :allow_nil option of validate_uniqueness_of. Closes 3143 [Caio Chassot]
  • Bring the sybase adapter up to scratch for 1.2 release. [jsheets]
  • Oracle: fix connection reset failure. 6846 [leonlleslie]
  • Subclass instantiation doesn‘t try to explicitly require the corresponding subclass. 6840 [leei, Jeremy Kemper]
  • fix faulty inheritance tests and that eager loading grabs the wrong inheritance column when the class of your association is an STI subclass. Closes 6859 [protocool]
  • find supports :lock with :include. Check whether your database allows SELECT … FOR UPDATE with outer joins before using. 6764 [vitaly, Jeremy Kemper]
  • Support nil and Array in :conditions => { attr => value } hashes. 6548 [Assaf, Jeremy Kemper]
      find(:all, :conditions => { :topic_id => [1, 2, 3], :last_read => nil }
  • Quote ActiveSupport::Multibyte::Chars. 6653 [Julian Tarkhanov]
  • MySQL: detect when a NOT NULL column without a default value is misreported as default ’’. Can‘t detect for string, text, and binary columns since ’’ is a legitimate default. 6156 [simon@redhillconsulting.com.au, obrie, Jonathan Viney, Jeremy Kemper]
  • validates_numericality_of uses \A \Z to ensure the entire string matches rather than ^ $ which may match one valid line of a multiline string. 5716 [Andreas Schwarz]
  • Oracle: automatically detect the primary key. 6594 [vesaria, Michael Schoen]
  • Oracle: to increase performance, prefetch 100 rows and enable similar cursor sharing. Both are configurable in database.yml. 6607 [philbogle@gmail.com, ray.fortna@jobster.com, Michael Schoen]
  • Firebird: decimal/numeric support. 6408 [macrnic]
  • Find with :include respects scoped :order. 5850
  • Dynamically generate reader methods for serialized attributes. 6362 [Stefan Kaes]
  • Deprecation: object transactions warning. [Jeremy Kemper]
  • has_one :dependent => :nullify ignores nil associates. 6528 [janovetz, Jeremy Kemper]
  • Oracle: resolve test failures, use prefetched primary key for inserts, check for null defaults, fix limited id selection for eager loading. Factor out some common methods from all adapters. 6515 [Michael Schoen]
  • Make add_column use the options hash with the Sqlite Adapter. Closes 6464 [obrie]
  • Document other options available to migration‘s add_column. 6419 [grg]
  • MySQL: all_hashes compatibility with old MysqlRes class. 6429, 6601 [Jeremy Kemper]
  • Fix has_many :through to add the appropriate conditions when going through an association using STI. Closes 5783. [Jonathan Viney]
  • fix select_limited_ids_list issues in postgresql, retain current behavior in other adapters [Rick]
  • Restore eager condition interpolation, document it‘s differences [Rick]
  • Don‘t rollback in teardown unless a transaction was started. Don‘t start a transaction in create_fixtures if a transaction is started. 6282 [Jacob Fugal, Jeremy Kemper]
  • Add delete support to has_many :through associations. Closes 6049 [Martin Landers]
  • Reverted old select_limited_ids_list postgresql fix that caused issues in mysql. Closes 5851 [Rick]
  • Removes the ability for eager loaded conditions to be interpolated, since there is no model instance to use as a context for interpolation. 5553 [turnip@turnipspatch.com]
  • Added timeout option to SQLite3 configurations to deal more gracefully with SQLite3::BusyException, now the connection can instead retry for x seconds to see if the db clears up before throwing that exception 6126 [wreese@gmail.com]
  • Added update_attributes! which uses save! to raise an exception if a validation error prevents saving 6192 [jonathan]
  • Deprecated add_on_boundary_breaking (use validates_length_of instead) 6292 [BobSilva]
  • The has_many create method works with polymorphic associations. 6361 [Dan Peterson]
  • MySQL: introduce Mysql::Result#all_hashes to support further optimization. 5581 [Stefan Kaes]
  • save! shouldn‘t validate twice. 6324 [maiha, Bob Silva]
  • Association collections have an _ids reader method to match the existing writer for collection_select convenience (e.g. employee.task_ids). The writer method skips blank ids so you can safely do @employee.task_ids = params[:tasks] without checking every time for an empty list or blank values. 1887, 5780 [Michael Schuerig]
  • Add an attribute reader method for ActiveRecord::Base.observers [Rick Olson]
  • Deprecation: count class method should be called with an options hash rather than two args for conditions and joins. 6287 [Bob Silva]
  • has_one associations with a nil target may be safely marshaled. 6279 [norbauer, Jeremy Kemper]
  • Duplicate the hash provided to AR::Base#to_xml to prevent unexpected side effects [Koz]
  • Add a :namespace option to AR::Base#to_xml [Koz]
  • Deprecation tests. Remove warnings for dynamic finders and for the foo_count method if it‘s also an attribute. [Jeremy Kemper]
  • Mock Time.now for more accurate Touch mixin tests. 6213 [Dan Peterson]
  • Improve yaml fixtures error reporting. 6205 [Bruce Williams]
  • Rename AR::Base#quote so people can use that name in their models. 3628 [Koz]
  • Add deprecation warning for inferred foreign key. 6029 [Josh Susser]
  • Fixed the Ruby/MySQL adapter we ship with Active Record to work with the new authentication handshake that was introduced in MySQL 4.1, along with the other protocol changes made at that time 5723 [jimw@mysql.com]
  • Deprecation: use :dependent => :delete_all rather than :exclusively_dependent => true. 6024 [Josh Susser]
  • Optimistic locking: gracefully handle nil versions, treat as zero. 5908 [Tom Ward]
  • to_xml: the :methods option works on arrays of records. 5845 [Josh Starcher]
  • has_many :through conditions are sanitized by the associating class. 5971 [martin.emde@gmail.com]
  • Fix spurious newlines and spaces in AR::Base#to_xml output [Jamis Buck]
  • has_one supports the :dependent => :delete option which skips the typical callback chain and deletes the associated object directly from the database. 5927 [Chris Mear, Jonathan Viney]
  • Nested subclasses are not prefixed with the parent class’ table_name since they should always use the base class’ table_name. 5911 [Jonathan Viney]
  • SQLServer: work around bug where some unambiguous date formats are not correctly identified if the session language is set to german. 5894 [Tom Ward, kruth@bfpi]
  • Clashing type columns due to a sloppy join shouldn‘t wreck single-table inheritance. 5838 [Kevin Clark]
  • Fixtures: correct escaping of \n and \r. 5859 [evgeny.zislis@gmail.com]
  • Migrations: gracefully handle missing migration files. 5857 [eli.gordon@gmail.com]
  • MySQL: update test schema for MySQL 5 strict mode. 5861 [Tom Ward]
  • to_xml: correct naming of included associations. 5831 [josh.starcher@gmail.com]
  • Pushing a record onto a has_many :through sets the association‘s foreign key to the associate‘s primary key and adds it to the correct association. 5815, 5829 [josh@hasmanythrough.com]
  • Add records to has_many :through using <<, push, and concat by creating the association record. Raise if base or associate are new records since both ids are required to create the association. build raises since you can‘t associate an unsaved record. create! takes an attributes hash and creates the associated record and its association in a transaction. [Jeremy Kemper]
      # Create a tagging to associate the post and tag.
  post.tags << Tag.find_by_name('old')
  post.tags.create! :name => 'general'

  # Would have been:
  post.taggings.create!(:tag => Tag.find_by_name('finally')
  transaction do
    post.taggings.create!(:tag => Tag.create!(:name => 'general'))
  end
  • Cache nil results for :included has_one associations also. 5787 [Michael Schoen]
  • Fixed a bug which would cause .save to fail after trying to access a empty has_one association on a unsaved record. [Tobias Luetke]
  • Nested classes are given table names prefixed by the singular form of the parent‘s table name. [Jeremy Kemper]
      Example: Invoice::Lineitem is given table name invoice_lineitems
  • Migrations: uniquely name multicolumn indexes so you don‘t have to. [Jeremy Kemper]
      # people_active_last_name_index, people_active_deactivated_at_index
  add_index    :people, [:active, :last_name]
  add_index    :people, [:active, :deactivated_at]
  remove_index :people, [:active, :last_name]
  remove_index :people, [:active, :deactivated_at]

    WARNING: backward-incompatibility. Multicolumn indexes created before this revision were named using the first column name only. Now they‘re uniquely named using all indexed columns.

    To remove an old multicolumn index, remove_index :table_name, :first_column

  • Fix for deep includes on the same association. [richcollins@gmail.com]
  • Tweak fixtures so they don‘t try to use a non-ActiveRecord class. [Kevin Clark]
  • Remove ActiveRecord::Base.reset since Dispatcher doesn‘t use it anymore. [Rick Olson]
  • PostgreSQL: autodetected sequences work correctly with multiple schemas. Rely on the schema search_path instead of explicitly qualifying the sequence name with its schema. 5280 [guy.naor@famundo.com]
  • Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
  • Cache nil results for has_one associations so multiple calls don‘t call the database. Closes 5757. [Michael A. Schoen]
  • Don‘t save has_one associations unnecessarily. 5735 [Jonathan Viney]
  • Refactor ActiveRecord::Base.reset_subclasses to reset, and add global observer resetting. [Rick Olson]
  • Formally deprecate the deprecated finders. [Koz]
  • Formally deprecate rich associations. [Koz]
  • Fixed that default timezones for new / initialize should uphold utc setting 5709 [daniluk@yahoo.com]
  • Fix announcement of very long migration names. 5722 [blake@near-time.com]
  • The exists? class method should treat a string argument as an id rather than as conditions. 5698 [jeremy@planetargon.com]
  • Fixed to_xml with :include misbehaviors when invoked on array of model instances 5690 [alexkwolfe@gmail.com]
  • Added support for conditions on Base.exists? 5689 [Josh Peek]. Examples:
      assert (Topic.exists?(:author_name => "David"))
        assert (Topic.exists?(:author_name => "Mary", :approved => true))
        assert (Topic.exists?(["parent_id = ?", 1]))
  • Schema dumper quotes date :default values. [Dave Thomas]
  • Calculate sum with SQL, not Enumerable on HasManyThrough Associations. [Dan Peterson]
  • Factor the attribute#{suffix} methods out of method_missing for easier extension. [Jeremy Kemper]
  • Patch sql injection vulnerability when using integer or float columns. [Jamis Buck]
  • Allow count through a has_many association to accept :include. [Dan Peterson]
  • create_table rdoc: suggest :id => false for habtm join tables. [Zed Shaw]
  • PostgreSQL: return array fields as strings. 4664 [Robby Russell]
  • SQLServer: added tests to ensure all database statements are closed, refactored identity_insert management code to use blocks, removed update/delete rowcount code out of execute and into update/delete, changed insert to go through execute method, removed unused quoting methods, disabled pessimistic locking tests as feature is currently unsupported, fixed RakeFile to load sqlserver specific tests whether running in ado or odbc mode, fixed support for recently added decimal types, added support for limits on integer types. 5670 [Tom Ward]
  • SQLServer: fix db:schema:dump case-sensitivity. 4684 [Will Rogers]
  • Oracle: BigDecimal support. 5667 [schoenm@earthlink.net]
  • Numeric and decimal columns map to BigDecimal instead of Float. Those with scale 0 map to Integer. 5454 [robbat2@gentoo.org, work@ashleymoran.me.uk]
  • Firebird migrations support. 5337 [Ken Kunz <kennethkunz@gmail.com>]
  • PostgreSQL: create/drop as postgres user. 4790 [mail@matthewpainter.co.uk, mlaster@metavillage.com]
  • PostgreSQL: correctly quote the ’ in pk_and_sequence_for. 5462 [tietew@tietew.net]
  • PostgreSQL: correctly quote microseconds in timestamps. 5641 [rick@rickbradley.com]
  • Clearer has_one/belongs_to model names (account has_one :user). 5632 [matt@mattmargolis.net]
  • Oracle: use nonblocking queries if allow_concurrency is set, fix pessimistic locking, don‘t guess date vs. time by default (set OracleAdapter.emulate_dates = true for the old behavior), adapter cleanup. 5635 [schoenm@earthlink.net]
  • Fixed a few Oracle issues: Allows Oracle‘s odd date handling to still work consistently within to_xml, Passes test that hardcode insert statement by dropping the :id column, Updated RUNNING_UNIT_TESTS with Oracle instructions, Corrects method signature for exec 5294 [schoenm@earthlink.net]
  • Added :group to available options for finds done on associations 5516 [mike@michaeldewey.org]
  • Observers also watch subclasses created after they are declared. 5535 [daniels@pronto.com.au]
  • Removed deprecated timestamps_gmt class methods. [Jeremy Kemper]
  • rake build_mysql_database grants permissions to rails@localhost. 5501 [brianegge@yahoo.com]
  • PostgreSQL: support microsecond time resolution. 5492 [alex@msgpad.com]
  • Add AssociationCollection#sum since the method_missing invokation has been shadowed by Enumerable#sum.
  • Added find_or_initialize_by_X which works like find_or_create_by_X but doesn‘t save the newly instantiated record. [Sam Stephenson]
  • Row locking. Provide a locking clause with the :lock finder option or true for the default "FOR UPDATE". Use the lock! method to obtain a row lock on a single record (reloads the record with :lock => true). [Shugo Maeda]
      # Obtain an exclusive lock on person 1 so we can safely increment visits.
  Person.transaction do
    # select * from people where id=1 for update
    person = Person.find(1, :lock => true)
    person.visits += 1
    person.save!
  end
  • PostgreSQL: introduce allow_concurrency option which determines whether to use blocking or asynchronous execute. Adapters with blocking execute will deadlock Ruby threads. The default value is ActiveRecord::Base.allow_concurrency. [Jeremy Kemper]
  • Use a per-thread (rather than global) transaction mutex so you may execute concurrent transactions on separate connections. [Jeremy Kemper]
  • Change AR::Base#to_param to return a String instead of a Fixnum. Closes 5320. [Nicholas Seckar]
  • Use explicit delegation instead of method aliasing for AR::Base.to_param -> AR::Base.id. 5299 (skaes@web.de)
  • Refactored ActiveRecord::Base.to_xml to become a delegate for XmlSerializer, which restores sanity to the mega method. This refactoring also reinstates the opinions that type="string" is redundant and ugly and nil-differentiation is not a concern of serialization [DHH]
  • Added simple hash conditions to find that‘ll just convert hash to an AND-based condition string 5143 [hcatlin@gmail.com]. Example:
      Person.find(:all, :conditions => { :last_name => "Catlin", :status => 1 }, :limit => 2)

…is the same as:

    Person.find(:all, :conditions => [ "last_name = ? and status = ?", "Catlin", 1 ], :limit => 2)

  This makes it easier to pass in the options from a form or otherwise outside.
  • Fixed issues with BLOB limits, charsets, and booleans for Firebird 5194, 5191, 5189 [kennethkunz@gmail.com]
  • Fixed usage of :limit and with_scope when the association in scope is a 1:m 5208 [alex@purefiction.net]
  • Fixed migration trouble with SQLite when NOT NULL is used in the new definition 5215 [greg@lapcominc.com]
  • Fixed problems with eager loading and counting on SQL Server 5212 [kajism@yahoo.com]
  • Fixed that count distinct should use the selected column even when using :include 5251 [anna@wota.jp]
  • Fixed that :includes merged from with_scope won‘t cause the same association to be loaded more than once if repetition occurs in the clauses 5253 [alex@purefiction.net]
  • Allow models to override to_xml. 4989 [Blair Zajac <blair@orcaware.com>]
  • PostgreSQL: don‘t ignore port when host is nil since it‘s often used to label the domain socket. 5247 [shimbo@is.naist.jp]
  • Records and arrays of records are bound as quoted ids. [Jeremy Kemper]
      Foo.find(:all, :conditions => ['bar_id IN (?)', bars])
  Foo.find(:first, :conditions => ['bar_id = ?', bar])
  • Fixed that Base.find :all, :conditions => [ "id IN (?)", collection ] would fail if collection was empty [DHH]
  • Add a list of regexes assert_queries skips in the ActiveRecord test suite. [Rick]
  • Fix the has_and_belongs_to_many create doesn‘t populate the join for new records. Closes 3692 [josh@hasmanythrough.com]
  • Provide Association Extensions access to the instance that the association is being accessed from. Closes 4433 [josh@hasmanythrough.com]
  • Update OpenBase adaterp‘s maintainer‘s email address. Closes 5176. [Derrick Spell]
  • Add a quick note about :select and eagerly included associations. [Rick]
  • Add docs for the :as option in has_one associations. Closes 5144 [cdcarter@gmail.com]
  • Fixed that has_many collections shouldn‘t load the entire association to do build or create [DHH]
  • Added :allow_nil option for aggregations 5091 [ian.w.white@gmail.com]
  • Fix Oracle boolean support and tests. Closes 5139. [schoenm@earthlink.net]
  • create! no longer blows up when no attributes are passed and a :create scope is in effect (e.g. foo.bars.create! failed whereas foo.bars.create!({}) didn‘t.) [Jeremy Kemper]
  • Call Inflector#demodulize on the class name when eagerly including an STI model. Closes 5077 [info@loobmedia.com]
  • Preserve MySQL boolean column defaults when changing a column in a migration. Closes 5015. [pdcawley@bofh.org.uk]
  • PostgreSQL: migrations support :limit with :integer columns by mapping limit < 4 to smallint, > 4 to bigint, and anything else to integer. 2900 [keegan@thebasement.org]
  • Dates and times interpret empty strings as nil rather than 2000-01-01. 4830 [kajism@yahoo.com]
  • Allow :uniq => true with has_many :through associations. [Jeremy Kemper]
  • Ensure that StringIO is always available for the Schema dumper. [Marcel Molina Jr.]
  • Allow AR::Base#to_xml to include methods too. Closes 4921. [johan@textdrive.com]
  • Remove duplicate fixture entry in comments.yml. Closes 4923. [Blair Zajac <blair@orcaware.com>]
  • When grouping, use the appropriate option key. [Marcel Molina Jr.]
  • Add support for FrontBase (www.frontbase.com/) with a new adapter thanks to the hard work of one Mike Laster. Closes 4093. [mlaster@metavillage.com]
  • Add warning about the proper way to validate the presence of a foreign key. Closes 4147. [Francois Beausoleil <francois.beausoleil@gmail.com>]
  • Fix syntax error in documentation. Closes 4679. [mislav@nippur.irb.hr]
  • Add Oracle support for CLOB inserts. Closes 4748. [schoenm@earthlink.net sandra.metz@duke.edu]
  • Various fixes for sqlserver_adapter (odbc statement finishing, ado schema dumper, drop index). Closes 4831. [kajism@yahoo.com]
  • Add support for :order option to with_scope. Closes 3887. [eric.daspet@survol.net]
  • Prettify output of schema_dumper by making things line up. Closes 4241 [Caio Chassot <caio@v2studio.com>]
  • Make build_postgresql_databases task make databases owned by the postgres user. Closes 4790. [mlaster@metavillage.com]
  • Sybase Adapter type conversion cleanup. Closes 4736. [dev@metacasa.net]
  • Fix bug where calculations with long alias names return null. [Rick]
  • Raise error when trying to add to a has_many :through association. Use the Join Model instead. [Rick]
      @post.tags << @tag                  # BAD
  @post.taggings.create(:tag => @tag) # GOOD
  • Allow all calculations to take the :include option, not just COUNT (closes 4840) [Rick]
  • Add ActiveRecord::Errors#to_xml [Jamis Buck]
  • Properly quote index names in migrations (closes 4764) [John Long]
  • Fix the HasManyAssociation#count method so it uses the new ActiveRecord::Base#count syntax, while maintaining backwards compatibility. [Rick]
  • 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]
  • Add :case_sensitive option to validates_uniqueness_of (closes 3090) [Rick]
      class Account < ActiveRecord::Base
    validates_uniqueness_of :email, :case_sensitive => false
  end
  • Allow multiple association extensions with :extend option (closes 4666) [Josh Susser]
      class Account < ActiveRecord::Base
    has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
  end

*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, 2006)

  • Fix type_name_with_module to handle type names that begin with ’::’. Closes 4614. [Nicholas Seckar]
  • Fixed that that multiparameter assignment doesn‘t work with aggregations (closes 4620) [Lars Pind]
  • Enable Limit/Offset in Calculations (closes 4558) [lmarlow@yahoo.com]
  • Fixed that loading including associations returns all results if Load IDs For Limited Eager Loading returns none (closes 4528) [Rick]
  • Fixed HasManyAssociation#find bugs when :finder_sql is set 4600 [lagroue@free.fr]
  • Allow AR::Base#respond_to? to behave when @attributes is nil [zenspider]
  • Support eager includes when going through a polymorphic has_many association. [Rick]
  • Added support for eagerly including polymorphic has_one associations. (closes 4525) [Rick]
      class Post < ActiveRecord::Base
    has_one :tagging, :as => :taggable
  end

  Post.find :all, :include => :tagging
  • Added descriptive error messages for invalid has_many :through associations: going through :has_one or :has_and_belongs_to_many [Rick]
  • Added support for going through a polymorphic has_many association: (closes 4401) [Rick]
      class PhotoCollection < ActiveRecord::Base
    has_many :photos, :as => :photographic
    belongs_to :firm
  end

  class Firm < ActiveRecord::Base
    has_many :photo_collections
    has_many :photos, :through => :photo_collections
  end
  • Multiple fixes and optimizations in PostgreSQL adapter, allowing ruby-postgres gem to work properly. [ruben.nine@gmail.com]
  • Fixed that AssociationCollection#delete_all should work even if the records of the association are not loaded yet. [Florian Weber]
  • Changed those private ActiveRecord methods to take optional third argument :auto instead of nil for performance optimizations. (closes 4456) [Stefan]
  • Private ActiveRecord methods add_limit!, add_joins!, and add_conditions! take an OPTIONAL third argument ‘scope’ (closes 4456) [Rick]
  • DEPRECATED: Using additional attributes on has_and_belongs_to_many associations. Instead upgrade your association to be a real join model [DHH]
  • Fixed that records returned from has_and_belongs_to_many associations with additional attributes should be marked as read only (fixes 4512) [DHH]
  • Do not implicitly mark recordss of has_many :through as readonly but do mark habtm records as readonly (eventually only on join tables without rich attributes). [Marcel Mollina Jr.]
  • Fixed broken OCIAdapter 4457 [schoenm@earthlink.net]

*1.14.0* (March 27th, 2006)

  • Replace ‘rescue Object’ with a finer grained rescue. Closes 4431. [Nicholas Seckar]
  • Fixed eager loading so that an aliased table cannot clash with a has_and_belongs_to_many join table [Rick]
  • Add support for :include to with_scope [andrew@redlinesoftware.com]
  • Support the use of public synonyms with the Oracle adapter; required ruby-oci8 v0.1.14 4390 [schoenm@earthlink.net]
  • Change periods (.) in table aliases to _‘s. Closes 4251 [jeff@ministrycentered.com]
  • Changed has_and_belongs_to_many join to INNER JOIN for Mysql 3.23.x. Closes 4348 [Rick]
  • Fixed issue that kept :select options from being scoped [Rick]
  • Fixed db_schema_import when binary types are present 3101 [DHH]
  • Fixed that MySQL enums should always be returned as strings 3501 [DHH]
  • Change has_many :through to use the :source option to specify the source association. :class_name is now ignored. [Rick Olson]
      class Connection < ActiveRecord::Base
    belongs_to :user
    belongs_to :channel
  end

  class Channel < ActiveRecord::Base
    has_many :connections
    has_many :contacts, :through => :connections, :class_name => 'User' # OLD
    has_many :contacts, :through => :connections, :source => :user      # NEW
  end
  • Fixed DB2 adapter so nullable columns will be determines correctly now and quotes from column default values will be removed 4350 [contact@maik-schmidt.de]
  • Allow overriding of find parameters in scoped has_many :through calls [Rick Olson]

    In this example, :include => false disables the default eager association from loading. :select changes the standard select clause. :joins specifies a join that is added to the end of the has_many :through query.

      class Post < ActiveRecord::Base
    has_many :tags, :through => :taggings, :include => :tagging do
      def add_joins_and_select
        find :all, :select => 'tags.*, authors.id as author_id', :include => false,
          :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id'
      end
    end
  end
  • Fixed that schema changes while the database was open would break any connections to a SQLite database (now we reconnect if that error is throw) [DHH]
  • Don‘t classify the has_one class when eager loading, it is already singular. Add tests. (closes 4117) [jonathan@bluewire.net.nz]
  • Quit ignoring default :include options in has_many :through calls [Mark James]
  • Allow has_many :through associations to find the source association by setting a custom class (closes 4307) [jonathan@bluewire.net.nz]
  • Eager Loading support added for has_many :through => :has_many associations (see below). [Rick Olson]
  • Allow has_many :through to work on has_many associations (closes 3864) [sco@scottraymond.net] Example:
      class Firm < ActiveRecord::Base
    has_many :clients
    has_many :invoices, :through => :clients
  end

  class Client < ActiveRecord::Base
    belongs_to :firm
    has_many   :invoices
  end

  class Invoice < ActiveRecord::Base
    belongs_to :client
  end
  • Raise error when trying to select many polymorphic objects with has_many :through or :include (closes 4226) [josh@hasmanythrough.com]
  • Fixed has_many :through to include :conditions set on the :through association. closes 4020 [jonathan@bluewire.net.nz]
  • Fix that has_many :through honors the foreign key set by the belongs_to association in the join model (closes 4259) [andylien@gmail.com / Rick]
  • SQL Server adapter gets some love 4298 [rtomayko@gmail.com]
  • Added OpenBase database adapter that builds on top of the www.spice-of-life.net/ruby-openbase/ driver. All functionality except LIMIT/OFFSET is supported 3528 [derrickspell@cdmplus.com]
  • Rework table aliasing to account for truncated table aliases. Add smarter table aliasing when doing eager loading of STI associations. This allows you to use the association name in the order/where clause. [Jonathan Viney / Rick Olson] 4108 Example (SpecialComment is using STI):
      Author.find(:all, :include => { :posts => :special_comments }, :order => 'special_comments.body')
  • Add AbstractAdapter#table_alias_for to create table aliases according to the rules of the current adapter. [Rick]
  • Provide access to the underlying database connection through Adapter#raw_connection. Enables the use of db-specific methods without complicating the adapters. 2090 [Koz]
  • Remove broken attempts at handling columns with a default of ‘now()’ in the postgresql adapter. 2257 [Koz]
  • Added connection#current_database that‘ll return of the current database (only works in MySQL, SQL Server, and Oracle so far — please help implement for the rest of the adapters) 3663 [Tom ward]
  • Fixed that Migration#execute would have the table name prefix appended to its query 4110 [mark.imbriaco@pobox.com]
  • Make all tinyint(1) variants act like boolean in mysql (tinyint(1) unsigned, etc.) [Jamis Buck]
  • Use association‘s :conditions when eager loading. [jeremyevans0@gmail.com] 4144
  • Alias the has_and_belongs_to_many join table on eager includes. 4106 [jeremyevans0@gmail.com]

    This statement would normally error because the projects_developers table is joined twice, and therefore joined_on would be ambiguous.

      Developer.find(:all, :include => {:projects => :developers}, :conditions => 'join_project_developers.joined_on IS NOT NULL')
  • Oracle adapter gets some love 4230 [schoenm@earthlink.net]
      * Changes :text to CLOB rather than BLOB [Moses Hohman]
  * Fixes an issue with nil numeric length/scales (several)
  * Implements support for XMLTYPE columns [wilig / Kubo Takehiro]
  * Tweaks a unit test to get it all green again
  * Adds support for #current_database
  • Added Base.abstract_class? that marks which classes are not part of the Active Record hierarchy 3704 [Rick Olson]
      class CachedModel < ActiveRecord::Base
    self.abstract_class = true
  end

  class Post < CachedModel
  end

  CachedModel.abstract_class?
  => true

  Post.abstract_class?
  => false

  Post.base_class
  => Post

  Post.table_name
  => 'posts'
  • Allow :dependent options to be used with polymorphic joins. 3820 [Rick Olson]
      class Foo < ActiveRecord::Base
    has_many :attachments, :as => :attachable, :dependent => :delete_all
  end
  • Nicer error message on has_many :through when :through reflection can not be found. 4042 [court3nay@gmail.com]
  • Upgrade to Transaction::Simple 1.3 [Jamis Buck]
  • Catch FixtureClassNotFound when using instantiated fixtures on a fixture that has no ActiveRecord model [Rick Olson]
  • Allow ordering of calculated results and/or grouped fields in calculations [solo@gatelys.com]
  • Make ActiveRecord::Base#save! return true instead of nil on success. 4173 [johan@johansorensen.com]
  • Dynamically set allow_concurrency. 4044 [Stefan Kaes]
  • Added Base#to_xml that‘ll turn the current record into a XML representation [DHH]. Example:
      topic.to_xml

    …returns:

      <?xml version="1.0" encoding="UTF-8"?>
  <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <id type="integer">1</id>
    <approved type="boolean">false</approved>
    <replies-count type="integer">0</replies-count>
    <bonus-time type="datetime">2000-01-01 08:28:00</bonus-time>
    <written-on type="datetime">2003-07-16 09:28:00</written-on>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

    …and you can configure with:

      topic.to_xml(:skip_instruct => true, :except => [ :id, bonus_time, :written_on, replies_count ])

    …that‘ll return:

      <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <approved type="boolean">false</approved>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

    You can even do load first-level associations as part of the document:

      firm.to_xml :include => [ :account, :clients ]

    …that‘ll return something like:

      <?xml version="1.0" encoding="UTF-8"?>
  <firm>
    <id type="integer">1</id>
    <rating type="integer">1</rating>
    <name>37signals</name>
    <clients>
      <client>
        <rating type="integer">1</rating>
        <name>Summit</name>
      </client>
      <client>
        <rating type="integer">1</rating>
        <name>Microsoft</name>
      </client>
    </clients>
    <account>
      <id type="integer">1</id>
      <credit-limit type="integer">50</credit-limit>
    </account>
  </firm>
  • Allow :counter_cache to take a column name for custom counter cache columns [Jamis Buck]
  • Documentation fixes for :dependent [robby@planetargon.com]
  • Stop the MySQL adapter crashing when views are present. 3782 [Jonathan Viney]
  • Don‘t classify the belongs_to class, it is already singular 4117 [keithm@infused.org]
  • Allow set_fixture_class to take Classes instead of strings for a class in a module. Raise FixtureClassNotFound if a fixture can‘t load. [Rick Olson]
  • Fix quoting of inheritance column for STI eager loading 4098 [Jonathan Viney <jonathan@bluewire.net.nz>]
  • Added smarter table aliasing for eager associations for multiple self joins 3580 [Rick Olson]
      * The first time a table is referenced in a join, no alias is used.
  * After that, the parent class name and the reflection name are used.

      Tree.find(:all, :include => :children) # LEFT OUTER JOIN trees AS tree_children ...

  * Any additional join references get a numerical suffix like '_2', '_3', etc.
  • Fixed eager loading problems with single-table inheritance 3580 [Rick Olson]. Post.find(:all, :include => :special_comments) now returns all posts, and any special comments that the posts may have. And made STI work with has_many :through and polymorphic belongs_to.
  • Added cascading eager loading that allows for queries like Author.find(:all, :include=> { :posts=> :comments }), which will fetch all authors, their posts, and the comments belonging to those posts in a single query (using LEFT OUTER JOIN) 3913 [anna@wota.jp]. Examples:
      # cascaded in two levels
  >> Author.find(:all, :include=>{:posts=>:comments})
  => authors
       +- posts
            +- comments

  # cascaded in two levels and normal association
  >> Author.find(:all, :include=>[{:posts=>:comments}, :categorizations])
  => authors
       +- posts
            +- comments
       +- categorizations

  # cascaded in two levels with two has_many associations
  >> Author.find(:all, :include=>{:posts=>[:comments, :categorizations]})
  => authors
       +- posts
            +- comments
            +- categorizations

  # cascaded in three levels
  >> Company.find(:all, :include=>{:groups=>{:members=>{:favorites}}})
  => companies
       +- groups
            +- members
                 +- favorites
  • Make counter cache work when replacing an association 3245 [eugenol@gmail.com]
  • Make migrations verbose [Jamis Buck]
  • Make counter_cache work with polymorphic belongs_to [Jamis Buck]
  • Fixed that calling HasOneProxy#build_model repeatedly would cause saving to happen 4058 [anna@wota.jp]
  • Added Sybase database adapter that relies on the Sybase Open Client bindings (see raa.ruby-lang.org/project/sybase-ctlib) 3765 [John Sheets]. It‘s almost completely Active Record compliant (including migrations), but has the following caveats:
      * Does not support DATE SQL column types; use DATETIME instead.
  * Date columns on HABTM join tables are returned as String, not Time.
  * Insertions are potentially broken for :polymorphic join tables
  * BLOB column access not yet fully supported
  • Clear stale, cached connections left behind by defunct threads. [Jeremy Kemper]
  • CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. Most AR usage is in single-threaded applications. [Jeremy Kemper]
  • Renamed the "oci" adapter to "oracle", but kept the old name as an alias 4017 [schoenm@earthlink.net]
  • Fixed that Base.save should always return false if the save didn‘t succeed, including if it has halted by before_save‘s 1861, 2477 [DHH]
  • Speed up class -> connection caching and stale connection verification. 3979 [Stefan Kaes]
  • Add set_fixture_class to allow the use of table name accessors with models which use set_table_name. [Kevin Clark]
  • Added that fixtures to placed in subdirectories of the main fixture files are also loaded 3937 [dblack@wobblini.net]
  • Define attribute query methods to avoid method_missing calls. 3677 [jonathan@bluewire.net.nz]
  • ActiveRecord::Base.remove_connection explicitly closes database connections and doesn‘t corrupt the connection cache. Introducing the disconnect! instance method for the PostgreSQL, MySQL, and SQL Server adapters; implementations for the others are welcome. 3591 [Simon Stapleton, Tom Ward]
  • Added support for nested scopes 3407 [anna@wota.jp]. Examples:
      Developer.with_scope(:find => { :conditions => "salary > 10000", :limit => 10 }) do
    Developer.find(:all)     # => SELECT * FROM developers WHERE (salary > 10000) LIMIT 10

    # inner rule is used. (all previous parameters are ignored)
    Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
      Developer.find(:all)   # => SELECT * FROM developers WHERE (name = 'Jamis')
    end

    # parameters are merged
    Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
      Developer.find(:all)   # => SELECT * FROM developers WHERE (( salary > 10000 ) AND ( name = 'Jamis' )) LIMIT 10
    end
  end
  • Fixed db2 connection with empty user_name and auth options 3622 [phurley@gmail.com]
  • Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes 3699 [Masao Mutoh]
  • Fixed that reflections would bleed across class boundaries in single-table inheritance setups 3796 [lars@pind.com]
  • Added calculations: Base.count, Base.average, Base.sum, Base.minimum, Base.maxmium, and the generic Base.calculate. All can be used with :group and :having. Calculations and statitics need no longer require custom SQL. 3958 [Rick Olson]. Examples:
      Person.average :age
  Person.minimum :age
  Person.maximum :age
  Person.sum :salary, :group => :last_name
  • Renamed Errors#count to Errors#size but kept an alias for the old name (and included an alias for length too) 3920 [contact@lukeredpath.co.uk]
  • Reflections don‘t attempt to resolve module nesting of association classes. Simplify type computation. [Jeremy Kemper]
  • Improved the Oracle OCI Adapter with better performance for column reflection (from 3210), fixes to migrations (from 3476 and 3742), tweaks to unit tests (from 3610), and improved documentation (from 2446) 3879 [Aggregated by schoenm@earthlink.net]
  • Fixed that the schema_info table used by ActiveRecord::Schema.define should respect table pre- and suffixes 3834 [rubyonrails@atyp.de]
  • Added :select option to Base.count that‘ll allow you to select something else than * to be counted on. Especially important for count queries using DISTINCT 3839 [skaes]
  • Correct syntax error in mysql DDL, and make AAACreateTablesTest run first [Bob Silva]
  • Allow :include to be used with has_many :through associations 3611 [Michael Schoen]
  • PostgreSQL: smarter schema dumps using pk_and_sequence_for(table). 2920 [Blair Zajac]
  • SQLServer: more compatible limit/offset emulation. 3779 [Tom Ward]
  • Polymorphic join support for has_one associations (has_one :foo, :as => :bar) 3785 [Rick Olson]
  • PostgreSQL: correctly parse negative integer column defaults. 3776 [bellis@deepthought.org]
  • Fix problems with count when used with :include [Jeremy Hopple and Kevin Clark]
  • ActiveRecord::RecordInvalid now states which validations failed in its default error message [Tobias Luetke]
  • Using AssociationCollection#build with arrays of hashes should call build, not create [DHH]
  • Remove definition of reloadable? from ActiveRecord::Base to make way for new Reloadable code. [Nicholas Seckar]
  • Fixed schema handling for DB2 adapter that didn‘t work: an initial schema could be set, but it wasn‘t used when getting tables and indexes 3678 [Maik Schmidt]
  • Support the :column option for remove_index with the PostgreSQL adapter. 3661 [shugo@ruby-lang.org]
  • Add documentation for add_index and remove_index. 3600 [Manfred Stienstra <m.stienstra@fngtps.com>]
  • If the OCI library is not available, raise an exception indicating as much. 3593 [schoenm@earthlink.net]
  • Add explicit :order in finder tests as postgresql orders results differently by default. 3577. [Rick Olson]
  • Make dynamic finders honor additional passed in :conditions. 3569 [Oleg Pudeyev <pudeyo@rpi.edu>, Marcel Molina Jr.]
  • Show a meaningful error when the DB2 adapter cannot be loaded due to missing dependencies. [Nicholas Seckar]
  • Make .count work for has_many associations with multi line finder sql [schoenm@earthlink.net]
  • Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jamis Buck]
  • Allow configuration of the column used for optimistic locking [wilsonb@gmail.com]
  • Don‘t hardcode ‘id’ in acts as list. [ror@philippeapril.com]
  • Fix date errors for SQLServer in association tests. 3406 [kevin.clark@gmal.com]
  • Escape database name in MySQL adapter when creating and dropping databases. 3409 [anna@wota.jp]
  • Disambiguate table names for columns in validates_uniquness_of‘s WHERE clause. 3423 [alex.borovsky@gmail.com]
  • .with_scope imposed create parameters now bypass attr_protected [Tobias Luetke]
  • Don‘t raise an exception when there are more keys than there are named bind variables when sanitizing conditions. [Marcel Molina Jr.]
  • Multiple enhancements and adjustments to DB2 adaptor. 3377 [contact@maik-schmidt.de]
  • Sanitize scoped conditions. [Marcel Molina Jr.]
  • Added option to Base.reflection_of_all_associations to specify a specific association to scope the call. For example Base.reflection_of_all_associations(:has_many) [DHH]
  • Added ActiveRecord::SchemaDumper.ignore_tables which tells SchemaDumper which tables to ignore. Useful for tables with funky column like the ones required for tsearch2. [TobiasLuetke]
  • SchemaDumper now doesn‘t fail anymore when there are unknown column types in the schema. Instead the table is ignored and a Comment is left in the schema.rb. [TobiasLuetke]
  • Fixed that saving a model with multiple habtm associations would only save the first one. 3244 [yanowitz-rubyonrails@quantumfoam.org, Florian Weber]
  • Fix change_column to work with PostgreSQL 7.x and 8.x. 3141 [wejn@box.cz, Rick Olson, Scott Barron]
  • removed :piggyback in favor of just allowing :select on :through associations. [Tobias Luetke]
  • made method missing delegation to class methods on relation target work on :through associations. [Tobias Luetke]
  • made .find() work on :through relations. [Tobias Luetke]
  • Fix typo in association docs. 3296. [Blair Zajac]
  • 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
  • MySQL: allow encoding option for mysql.rb driver. [Jeremy Kemper]
  • Added option inheritance for find calls on has_and_belongs_to_many and has_many assosociations [DHH]. Example:
      class Post
    has_many :recent_comments, :class_name => "Comment", :limit => 10, :include => :author
  end

  post.recent_comments.find(:all) # Uses LIMIT 10 and includes authors
  post.recent_comments.find(:all, :limit => nil) # Uses no limit but include authors
  post.recent_comments.find(:all, :limit => nil, :include => nil) # Uses no limit and doesn't include authors
  • Added option to specify :group, :limit, :offset, and :select options from find on has_and_belongs_to_many and has_many assosociations [DHH]
  • MySQL: fixes for the bundled mysql.rb driver. 3160 [Justin Forder]
  • SQLServer: fix obscure optimistic locking bug. 3068 [kajism@yahoo.com]
  • SQLServer: support uniqueidentifier columns. 2930 [keithm@infused.org]
  • SQLServer: cope with tables names qualified by owner. 3067 [jeff@ministrycentered.com]
  • SQLServer: cope with columns with "desc" in the name. 1950 [Ron Lusk, Ryan Tomayko]
  • SQLServer: cope with primary keys with "select" in the name. 3057 [rdifrango@captechventures.com]
  • Oracle: active? performs a select instead of a commit. 3133 [Michael Schoen]
  • MySQL: more robust test for nullified result hashes. 3124 [Stefan Kaes]
  • Reloading an instance refreshes its aggregations as well as its associations. 3024 [François Beausoleil]
  • Fixed that using :include together with :conditions array in Base.find would cause NoMethodError 2887 [Paul Hammmond]
  • PostgreSQL: more robust sequence name discovery. 3087 [Rick Olson]
  • Oracle: use syntax compatible with Oracle 8. 3131 [Michael Schoen]
  • MySQL: work around ruby-mysql/mysql-ruby inconsistency with mysql.stat. Eliminate usage of mysql.ping because it doesn‘t guarantee reconnect. Explicitly close and reopen the connection instead. [Jeremy Kemper]
  • Added preliminary support for polymorphic associations [DHH]
  • Added preliminary support for join models [DHH]
  • Allow validate_uniqueness_of to be scoped by more than just one column. 1559. [jeremy@jthopple.com, Marcel Molina Jr.]
  • Firebird: active? and reconnect! methods for handling stale connections. 428 [Ken Kunz <kennethkunz@gmail.com>]
  • Firebird: updated for FireRuby 0.4.0. 3009 [Ken Kunz <kennethkunz@gmail.com>]
  • MySQL and PostgreSQL: active? compatibility with the pure-Ruby driver. 428 [Jeremy Kemper]
  • Oracle: active? check pings the database rather than testing the last command status. 428 [Michael Schoen]
  • SQLServer: resolve column aliasing/quoting collision when using limit or offset in an eager find. 2974 [kajism@yahoo.com]
  • Reloading a model doesn‘t lose track of its connection. 2996 [junk@miriamtech.com, Jeremy Kemper]
  • Fixed bug where using update_attribute after pushing a record to a habtm association of the object caused duplicate rows in the join table. 2888 [colman@rominato.com, Florian Weber, Michael Schoen]
  • MySQL, PostgreSQL: reconnect! also reconfigures the connection. Otherwise, the connection ‘loses’ its settings if it times out and is reconnected. 2978 [Shugo Maeda]
  • has_and_belongs_to_many: use JOIN instead of LEFT JOIN. [Jeremy Kemper]
  • MySQL: introduce :encoding option to specify the character set for client, connection, and results. Only available for MySQL 4.1 and later with the mysql-ruby driver. Do SHOW CHARACTER SET in mysql client to see available encodings. 2975 [Shugo Maeda]
  • Add tasks to create, drop and rebuild the MySQL and PostgreSQL test databases. [Marcel Molina Jr.]
  • Correct boolean handling in generated reader methods. 2945 [don.park@gmail.com, Stefan Kaes]
  • Don‘t generate read methods for columns whose names are not valid ruby method names. 2946 [Stefan Kaes]
  • Document :force option to create_table. 2921 [Blair Zajac <blair@orcaware.com>]
  • Don‘t add the same conditions twice in has_one finder sql. 2916 [Jeremy Evans]
  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]
  • Introducing the Firebird adapter. Quote columns and use attribute_condition more consistently. Setup guide: wiki.rubyonrails.com/rails/pages/Firebird+Adapter 1874 [Ken Kunz <kennethkunz@gmail.com>]
  • SQLServer: active? and reconnect! methods for handling stale connections. 428 [kajism@yahoo.com, Tom Ward <tom@popdog.net>]
  • Associations handle case-equality more consistently: item.parts.is_a?(Array) and item.parts === Array. 1345 [MarkusQ@reality.com]
  • SQLServer: insert uses given primary key value if not nil rather than SELECT @@IDENTITY. 2866 [kajism@yahoo.com, Tom Ward <tom@popdog.net>]
  • Oracle: active? and reconnect! methods for handling stale connections. Optionally retry queries after reconnect. 428 [Michael Schoen <schoenm@earthlink.net>]
  • Correct documentation for Base.delete_all. 1568 [Newhydra]
  • Oracle: test case for column default parsing. 2788 [Michael Schoen <schoenm@earthlink.net>]
  • Update documentation for Migrations. 2861 [Tom Werner <tom@cube6media.com>]
  • When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL, MySQL, and SQLite. Make certain that all statements which may need reconnection are performed within a logged block: for example, this means no avoiding log(sql, name) { } if @logger.nil? 428 [Jeremy Kemper]
  • Oracle: Much faster column reflection. 2848 [Michael Schoen <schoenm@earthlink.net>]
  • Base.reset_sequence_name analogous to reset_table_name (mostly useful for testing). Base.define_attr_method allows nil values. [Jeremy Kemper]
  • PostgreSQL: smarter sequence name defaults, stricter last_insert_id, warn on pk without sequence. [Jeremy Kemper]
  • PostgreSQL: correctly discover custom primary key sequences. 2594 [Blair Zajac <blair@orcaware.com>, meadow.nnick@gmail.com, Jeremy Kemper]
  • SQLServer: don‘t report limits for unsupported field types. 2835 [Ryan Tomayko]
  • Include the Enumerable module in ActiveRecord::Errors. [Rick Bradley <rick@rickbradley.com>]
  • Add :group option, correspond to GROUP BY, to the find method and to the has_many association. 2818 [rubyonrails@atyp.de]
  • Don‘t cast nil or empty strings to a dummy date. 2789 [Rick Bradley <rick@rickbradley.com>]
  • acts_as_list plays nicely with inheritance by remembering the class which declared it. 2811 [rephorm@rephorm.com]
  • Fix sqlite adaptor‘s detection of missing dbfile or database declaration. [Nicholas Seckar]
  • Fixed acts_as_list for definitions without an explicit :order 2803 [jonathan@bluewire.net.nz]
  • Upgrade bundled ruby-mysql 0.2.4 with mysql411 shim (see 440) to ruby-mysql 0.2.6 with a patchset for 4.1 protocol support. Local change [301] is now a part of the main driver; reapplied local change [2182]. Removed GC.start from Result.free. [tommy@tmtm.org, akuroda@gmail.com, Doug Fales <doug.fales@gmail.com>, Jeremy Kemper]
  • Correct handling of complex order clauses with SQL Server limit emulation. 2770 [Tom Ward <tom@popdog.net>, Matt B.]
  • Correct whitespace problem in Oracle default column value parsing. 2788 [rick@rickbradley.com]
  • Destroy associated has_and_belongs_to_many records after all before_destroy callbacks but before destroy. This allows you to act on the habtm association as you please while preserving referential integrity. 2065 [larrywilliams1@gmail.com, sam.kirchmeier@gmail.com, elliot@townx.org, Jeremy Kemper]
  • Deprecate the old, confusing :exclusively_dependent option in favor of :dependent => :delete_all. [Jeremy Kemper]
  • More compatible Oracle column reflection. 2771 [Ryan Davis <ryand-ruby@zenspider.com>, Michael Schoen <schoenm@earthlink.net>]

*1.13.0* (November 7th, 2005)

  • Fixed faulty regex in get_table_name method (SQLServerAdapter) 2639 [Ryan Tomayko]
  • Added :include as an option for association declarations [DHH]. Example:
      has_many :posts, :include => [ :author, :comments ]
  • Rename Base.constrain to Base.with_scope so it doesn‘t conflict with existing concept of database constraints. Make scoping more robust: uniform method => parameters, validated method names and supported finder parameters, raise exception on nested scopes. [Jeremy Kemper] Example:
      Comment.with_scope(:find => { :conditions => 'active=true' }, :create => { :post_id => 5 }) do
    # Find where name = ? and active=true
    Comment.find :all, :conditions => ['name = ?', name]
    # Create comment associated with :post_id
    Comment.create :body => "Hello world"
  end
  • Fixed that SQL Server should ignore :size declarations on anything but integer and string in the agnostic schema representation 2756 [Ryan Tomayko]
  • Added constrain scoping for creates using a hash of attributes bound to the :creation key [DHH]. Example:
      Comment.constrain(:creation => { :post_id => 5 }) do
    # Associated with :post_id
    Comment.create :body => "Hello world"
  end

    This is rarely used directly, but allows for find_or_create on associations. So you can do:

      # If the tag doesn't exist, a new one is created that's associated with the person
  person.tags.find_or_create_by_name("Summer")
  • Added find_or_create_by_X as a second type of dynamic finder that‘ll create the record if it doesn‘t already exist [DHH]. Example:
      # No 'Summer' tag exists
  Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")

  # Now the 'Summer' tag does exist
  Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
  • Added extension capabilities to has_many and has_and_belongs_to_many proxies [DHH]. Example:
      class Account < ActiveRecord::Base
    has_many :people do
      def find_or_create_by_name(name)
        first_name, *last_name = name.split
        last_name = last_name.join " "

        find_or_create_by_first_name_and_last_name(first_name, last_name)
      end
    end
  end

  person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson")
  person.first_name # => "David"
  person.last_name  # => "Heinemeier Hansson"

    Note that the anoymous module must be declared using brackets, not do/end (due to order of evaluation).

  • Omit internal dtproperties table from SQLServer table list. 2729 [rtomayko@gmail.com]
  • Quote column names in generated SQL. 2728 [rtomayko@gmail.com]
  • Correct the pure-Ruby MySQL 4.1.1 shim‘s version test. 2718 [Jeremy Kemper]
  • Add Model.create! to match existing model.save! method. When save! raises RecordInvalid, you can catch the exception, retrieve the invalid record (invalid_exception.record), and see its errors (invalid_exception.record.errors). [Jeremy Kemper]
  • Correct fixture behavior when table name pluralization is off. 2719 [Rick Bradley <rick@rickbradley.com>]
  • Changed :dbfile to :database for SQLite adapter for consistency (old key still works as an alias) 2644 [Dan Peterson]
  • Added migration support for Oracle 2647 [Michael Schoen]
  • Worked around that connection can‘t be reset if allow_concurrency is off. 2648 [Michael Schoen <schoenm@earthlink.net>]
  • Fixed SQL Server adapter to pass even more tests and do even better 2634 [rtomayko@gmail.com]
  • Fixed SQL Server adapter so it honors options[:conditions] when applying :limits 1978 [Tom Ward]
  • Added migration support to SQL Server adapter (please someone do the same for Oracle and DB2) 2625 [Tom Ward]
  • Use AR::Base.silence rather than AR::Base.logger.silence in fixtures to preserve Log4r compatibility. 2618 [dansketcher@gmail.com]
  • Constraints are cloned so they can‘t be inadvertently modified while they‘re

in effect. Added :readonly finder constraint. Calling an association collection‘s class method (Part.foobar via item.parts.foobar) constrains :readonly => false since the collection‘s :joins constraint would otherwise force it to true. [Jeremy Kemper <rails@bitsweat.net>]

  • Added :offset and :limit to the kinds of options that Base.constrain can use 2466 [duane.johnson@gmail.com]
  • Fixed handling of nil number columns on Oracle and cleaned up tests for Oracle in general 2555 [schoenm@earthlink.net]
  • Added quoted_true and quoted_false methods and tables to db2_adapter and cleaned up tests for DB2 2493, 2624 [maik schmidt]

*1.12.2* (October 26th, 2005)

  • Allow symbols to rename columns when using SQLite adapter. 2531 [kevin.clark@gmail.com]
  • Map Active Record time to SQL TIME. 2575, 2576 [Robby Russell <robby@planetargon.com>]
  • Clarify semantics of ActiveRecord::Base#respond_to? 2560 [skaes@web.de]
  • Fixed Association#clear for associations which have not yet been accessed. 2524 [Patrick Lenz <patrick@lenz.sh>]
  • HABTM finders shouldn‘t return readonly records. 2525 [Patrick Lenz <patrick@lenz.sh>]
  • Make all tests runnable on their own. 2521. [Blair Zajac <blair@orcaware.com>]

*1.12.1* (October 19th, 2005)

  • Always parenthesize :conditions options so they may be safely combined with STI and constraints.
  • Correct PostgreSQL primary key sequence detection. 2507 [tmornini@infomania.com]
  • Added support for using limits in eager loads that involve has_many and has_and_belongs_to_many associations

*1.12.0* (October 16th, 2005)

  • Update/clean up documentation (rdoc)
  • PostgreSQL sequence support. Use set_sequence_name in your model class to specify its primary key sequence. 2292 [Rick Olson <technoweenie@gmail.com>, Robby Russell <robby@planetargon.com>]
  • Change default logging colors to work on both white and black backgrounds. [Sam Stephenson]
  • YAML fixtures support ordered hashes for fixtures with foreign key dependencies in the same table. 1896 [purestorm@ggnore.net]
  • :dependent now accepts :nullify option. Sets the foreign key of the related objects to NULL instead of deleting them. 2015 [Robby Russell <robby@planetargon.com>]
  • Introduce read-only records. If you call object.readonly! then it will mark the object as read-only and raise ReadOnlyRecord if you call object.save. object.readonly? reports whether the object is read-only. Passing :readonly => true to any finder method will mark returned records as read-only. The :joins option now implies :readonly, so if you use this option, saving the same record will now fail. Use find_by_sql to work around.
  • Avoid memleak in dev mode when using fcgi
  • Simplified .clear on active record associations by using the existing delete_records method. 1906 [Caleb <me@cpb.ca>]
  • Delegate access to a customized primary key to the conventional id method. 2444. [Blair Zajac <blair@orcaware.com>]
  • Fix errors caused by assigning a has-one or belongs-to property to itself
  • Add ActiveRecord::Base.schema_format setting which specifies how databases should be dumped [Sam Stephenson]
  • Update DB2 adapter. 2206. [contact@maik-schmidt.de]
  • Corrections to SQLServer native data types. 2267. [rails.20.clarry@spamgourmet.com]
  • Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveRecord::Base.allow_concurrency.
  • Protect id attribute from mass assigment even when the primary key is set to something else. 2438. [Blair Zajac <blair@orcaware.com>]
  • Misc doc fixes (typos/grammar/etc.). 2430. [coffee2code]
  • Add test coverage for content_columns. 2432. [coffee2code]
  • Speed up for unthreaded environments. 2431. [skaes@web.de]
  • Optimization for Mysql selects using mysql-ruby extension greater than 2.6.3. 2426. [skaes@web.de]
  • Speed up the setting of table_name. 2428. [skaes@web.de]
  • Optimize instantiation of STI subclass records. In partial fullfilment of 1236. [skaes@web.de]
  • Fix typo of ‘constrains’ to ‘contraints’. 2069. [Michael Schuerig <michael@schuerig.de>]
  • Optimization refactoring for add_limit_offset!. In partial fullfilment of 1236. [skaes@web.de]
  • Add ability to get all siblings, including the current child, with acts_as_tree. Recloses 2140. [Michael Schuerig <michael@schuerig.de>]
  • Add geometric type for postgresql adapter. 2233 [akaspick@gmail.com]
  • Add option (true by default) to generate reader methods for each attribute of a record to avoid the overhead of calling method missing. In partial fullfilment of 1236. [skaes@web.de]
  • Add convenience predicate methods on Column class. In partial fullfilment of 1236. [skaes@web.de]
  • Raise errors when invalid hash keys are passed to ActiveRecord::Base.find. 2363 [Chad Fowler <chad@chadfowler.com>, Nicholas Seckar]
  • Added :force option to create_table that‘ll try to drop the table if it already exists before creating
  • Fix transactions so that calling return while inside a transaction will not leave an open transaction on the connection. [Nicholas Seckar]
  • Use foreign_key inflection uniformly. 2156 [Blair Zajac <blair@orcaware.com>]
  • model.association.clear should destroy associated objects if :dependent => true instead of nullifying their foreign keys. 2221 [joergd@pobox.com, ObieFernandez <obiefernandez@gmail.com>]
  • Returning false from before_destroy should cancel the action. 1829 [Jeremy Huffman]
  • Recognize PostgreSQL NOW() default as equivalent to CURRENT_TIMESTAMP or CURRENT_DATE, depending on the column‘s type. 2256 [mat <mat@absolight.fr>]
  • Extensive documentation for the abstract database adapter. 2250 [François Beausoleil <fbeausoleil@ftml.net>]
  • Clean up Fixtures.reset_sequences for PostgreSQL. Handle tables with no rows and models with custom primary keys. 2174, 2183 [jay@jay.fm, Blair Zajac <blair@orcaware.com>]
  • Improve error message when nil is assigned to an attr which validates_size_of within a range. 2022 [Manuel Holtgrewe <purestorm@ggnore.net>]
  • Make update_attribute use the same writer method that update_attributes uses.
 #2237 [trevor@protocool.com]
  • Make migrations honor table name prefixes and suffixes. 2298 [Jakob S, Marcel Molina]
  • Correct and optimize PostgreSQL bytea escaping. 1745, 1837 [dave@cherryville.org, ken@miriamtech.com, bellis@deepthought.org]
  • Fixtures should only reset a PostgreSQL sequence if it corresponds to an integer primary key named id. 1749 [chris@chrisbrinker.com]
  • Standardize the interpretation of boolean columns in the Mysql and Sqlite adapters. (Use MysqlAdapter.emulate_booleans = false to disable this behavior)
  • Added new symbol-driven approach to activating observers with Base#observers= [DHH]. Example:
      ActiveRecord::Base.observers = :cacher, :garbage_collector
  • Added AbstractAdapter#select_value and AbstractAdapter#select_values as convenience methods for selecting single values, instead of hashes, of the first column in a SELECT 2283 [solo@gatelys.com]
  • Wrap :conditions in parentheses to prevent problems with OR‘s 1871 [Jamis Buck]
  • Allow the postgresql adapter to work with the SchemaDumper. [Jamis Buck]
  • Add ActiveRecord::SchemaDumper for dumping a DB schema to a pure-ruby file, making it easier to consolidate large migration lists and port database schemas between databases. [Jamis Buck]
  • Fixed migrations for Windows when using more than 10 [David Naseby]
  • Fixed that the create_x method from belongs_to wouldn‘t save the association properly 2042 [Florian Weber]
  • Fixed saving a record with two unsaved belongs_to associations pointing to the same object 2023 [Tobias Luetke]
  • Improved migrations’ behavior when the schema_info table is empty. [Nicholas Seckar]
  • Fixed that Observers didn‘t observe sub-classes 627 [Florian Weber]
  • Fix eager loading error messages, allow :include to specify tables using strings or symbols. Closes 2222 [Marcel Molina]
  • Added check for RAILS_CONNECTION_ADAPTERS on startup and only load the connection adapters specified within if its present (available in Rails through config.connection_adapters using the new config) 1958 [skae]
  • Fixed various problems with has_and_belongs_to_many when using customer finder_sql 2094 [Florian Weber]
  • Added better exception error when unknown column types are used with migrations 1814 [fbeausoleil@ftml.net]
  • Fixed "connection lost" issue with the bundled Ruby/MySQL driver (would kill the app after 8 hours of inactivity) 2163, 428 [kajism@yahoo.com]
  • Fixed comparison of Active Record objects so two new objects are not equal 2099 [deberg]
  • Fixed that the SQL Server adapter would sometimes return DBI::Timestamp objects instead of Time 2127 [Tom Ward]
  • Added the instance methods root and ancestors on acts_as_tree and fixed siblings to not include the current node 2142, 2140 [coffee2code]
  • Fixed that Active Record would call SHOW FIELDS twice (or more) for the same model when the cached results were available 1947 [sd@notso.net]
  • Added log_level and use_silence parameter to ActiveRecord::Base.benchmark. The first controls at what level the benchmark statement will be logged (now as debug, instead of info) and the second that can be passed false to include all logging statements during the benchmark block/
  • Make sure the schema_info table is created before querying the current version 1903
  • Fixtures ignore table name prefix and suffix 1987 [Jakob S]
  • Add documentation for index_type argument to add_index method for migrations 2005 [blaine@odeo.com]
  • Modify read_attribute to allow a symbol argument 2024 [Ken Kunz]
  • Make destroy return self 1913 [sebastian.kanthak@muehlheim.de]
  • Fix typo in validations documentation 1938 [court3nay]
  • Make acts_as_list work for insert_at(1) 1966 [hensleyl@papermountain.org]
  • Fix typo in count_by_sql documentation 1969 [Alexey Verkhovsky]
  • Allow add_column and create_table to specify NOT NULL 1712 [emptysands@gmail.com]
  • Fix create_table so that id column is implicitly added [Rick Olson]
  • Default sequence names for Oracle changed to #{table_name}_seq, which is the most commonly used standard. In addition, a new method ActiveRecord::Base#set_sequence_name allows the developer to set the sequence name per model. This is a non-backwards-compatible change — anyone using the old-style "rails_sequence" will need to either create new sequences, or set: ActiveRecord::Base.set_sequence_name = "rails_sequence" 1798
  • OCIAdapter now properly handles synonyms, which are commonly used to separate out the schema owner from the application user 1798
  • Fixed the handling of camelCase columns names in Oracle 1798
  • Implemented for OCI the Rakefile tasks of :clone_structure_to_test, :db_structure_dump, and :purge_test_database, which enable Oracle folks to enjoy all the agile goodness of Rails for testing. Note that the current implementation is fairly limited — only tables and sequences are cloned, not constraints or indexes. A full clone in Oracle generally requires some manual effort, and is version-specific. Post 9i, Oracle recommends the use of the DBMS_METADATA package, though that approach requires editing of the physical characteristics generated 1798
  • Fixed the handling of multiple blob columns in Oracle if one or more of them are null 1798
  • Added support for calling constrained class methods on has_many and has_and_belongs_to_many collections 1764 [Tobias Luetke]
      class Comment < AR:B
    def self.search(q)
      find(:all, :conditions => ["body = ?", q])
    end
  end

  class Post < AR:B
    has_many :comments
  end

  Post.find(1).comments.search('hi') # => SELECT * from comments WHERE post_id = 1 AND body = 'hi'

    NOTICE: This patch changes the underlying SQL generated by has_and_belongs_to_many queries. If your relying on that, such as by explicitly referencing the old t and j aliases, you‘ll need to update your code. Of course, you _shouldn‘t_ be relying on details like that no less than you should be diving in to touch private variables. But just in case you do, consider yourself noticed :)

  • Added migration support for SQLite (using temporary tables to simulate ALTER TABLE) 1771 [Sam Stephenson]
  • Remove extra definition of supports_migrations? from abstract_adaptor.rb [Nicholas Seckar]
  • Fix acts_as_list so that moving next-to-last item to the bottom does not result in duplicate item positions
  • Fixed incompatibility in DB2 adapter with the new limit/offset approach 1718 [Maik Schmidt]
  • Added :select option to find which can specify a different value than the default *, like find(:all, :select => "first_name, last_name"), if you either only want to select part of the columns or exclude columns otherwise included from a join 1338 [Stefan Kaes]

*1.11.1* (11 July, 2005)

  • Added support for limit and offset with eager loading of has_one and belongs_to associations. Using the options with has_many and has_and_belongs_to_many associations will now raise an ActiveRecord::ConfigurationError 1692 [Rick Olsen]
  • Fixed that assume_bottom_position (in acts_as_list) could be called on items already last in the list and they would move one position away from the list 1648 [tyler@kianta.com]
  • Added ActiveRecord::Base.threaded_connections flag to turn off 1-connection per thread (required for thread safety). By default it‘s on, but WEBrick in Rails need it off 1685 [Sam Stephenson]
  • Correct reflected table name for singular associations. 1688 [court3nay@gmail.com]
  • Fixed optimistic locking with SQL Server 1660 [tom@popdog.net]
  • Added ActiveRecord::Migrator.migrate that can figure out whether to go up or down based on the target version and the current
  • Added better error message for "packets out of order" 1630 [courtenay]
  • Fixed first run of "rake migrate" on PostgreSQL by not expecting a return value on the id 1640

*1.11.0* (6 July, 2005)

  • Fixed that Yaml error message in fixtures hid the real error 1623 [Nicholas Seckar]
  • Changed logging of SQL statements to use the DEBUG level instead of INFO
  • Added new Migrations framework for describing schema transformations in a way that can be easily applied across multiple databases 1604 [Tobias Luetke] See documentation under ActiveRecord::Migration and the additional support in the Rails rakefile/generator.
  • Added callback hooks to association collections 1549 [Florian Weber]. Example:
      class Project
    has_and_belongs_to_many :developers, :before_add => :evaluate_velocity

    def evaluate_velocity(developer)
      ...
    end
  end

    ..raising an exception will cause the object not to be added (or removed, with before_remove).

  • Fixed Base.content_columns call for SQL Server adapter 1450 [DeLynn Berry]
  • Fixed Base#write_attribute to work with both symbols and strings 1190 [Paul Legato]
  • Fixed that has_and_belongs_to_many didn‘t respect single table inheritance types 1081 [Florian Weber]
  • Speed up ActiveRecord#method_missing for the common case (read_attribute).
  • Only notify observers on after_find and after_initialize if these methods are defined on the model. 1235 [skaes@web.de]
  • Fixed that single-table inheritance sub-classes couldn‘t be used to limit the result set with eager loading 1215 [Chris McGrath]
  • Fixed validates_numericality_of to work with overrided getter-method when :allow_nil is on 1316 [raidel@onemail.at]
  • Added roots, root, and siblings to the batch of methods added by acts_as_tree 1541 [michael@schuerig.de]
  • Added support for limit/offset with the MS SQL Server driver so that pagination will now work 1569 [DeLynn Berry]
  • Added support for ODBC connections to MS SQL Server so you can connect from a non-Windows machine 1569 [Mark Imbriaco/DeLynn Berry]
  • Fixed that multiparameter posts ignored attr_protected 1532 [alec+rails@veryclever.net]
  • Fixed problem with eager loading when using a has_and_belongs_to_many association using :association_foreign_key 1504 [flash@vanklinkenbergsoftware.nl]
  • Fixed Base#find to honor the documentation on how :joins work and make them consistent with Base#count 1405 [pritchie@gmail.com]. What used to be:
      Developer.find :all, :joins => 'developers_projects', :conditions => 'id=developer_id AND project_id=1'

    …should instead be:

      Developer.find(
    :all,
    :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
    :conditions => 'project_id=1'
  )
  • Fixed that validations didn‘t respecting custom setting for too_short, too_long messages 1437 [Marcel Molina]
  • Fixed that clear_association_cache doesn‘t delete new associations on new records (so you can safely place new records in the session with Action Pack without having new associations wiped) 1494 [cluon]
  • Fixed that calling Model.find([]) returns [] and doesn‘t throw an exception 1379
  • Fixed that adding a record to a has_and_belongs_to collection would always save it — now it only saves if its a new record 1203 [Alisdair McDiarmid]
  • Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save — that way you can add new associations in after_create/after_update callbacks without getting them saved twice
  • Allow any Enumerable, not just Array, to work as bind variables 1344 [Jeremy Kemper]
  • Added actual database-changing behavior to collection assigment for has_many and has_and_belongs_to_many 1425 [Sebastian Kanthak]. Example:
      david.projects = [Project.find(1), Project.new("name" => "ActionWebSearch")]
  david.save

    If david.projects already contain the project with ID 1, this is left unchanged. Any other projects are dropped. And the new project is saved when david.save is called.

    Also included is a way to do assignments through IDs, which is perfect for checkbox updating, so you get to do:

      david.project_ids = [1, 5, 7]
  • Corrected typo in find SQL for has_and_belongs_to_many. 1312 [ben@bensinclair.com]
  • Fixed sanitized conditions for has_many finder method. 1281 [jackc@hylesanderson.com, pragdave, Tobias Luetke]
  • Comprehensive PostgreSQL schema support. Use the optional schema_search_path directive in database.yml to give a comma-separated list of schemas to search for your tables. This allows you, for example, to have tables in a shared schema without having to use a custom table name. See www.postgresql.org/docs/8.0/interactive/ddl-schemas.html to learn more. 827 [dave@cherryville.org]
  • Corrected @@configurations typo 1410 [david@ruppconsulting.com]
  • Return PostgreSQL columns in the order they were declared 1374 [perlguy@gmail.com]
  • Allow before/after update hooks to work on models using optimistic locking
  • Eager loading of dependent has_one associations won‘t delete the association 1212
  • Added a second parameter to the build and create method for has_one that controls whether the existing association should be replaced (which means nullifying its foreign key as well). By default this is true, but false can be passed to prevent it.
  • Using transactional fixtures now causes the data to be loaded only once.
  • Added fixture accessor methods that can be used when instantiated fixtures are disabled.
      fixtures :web_sites

  def test_something
    assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
  end
  • Added DoubleRenderError exception that‘ll be raised if render* is called twice 518 [Nicholas Seckar]
  • Fixed exceptions occuring after render has been called 1096 [Nicholas Seckar]
  • CHANGED: validates_presence_of now uses Errors#add_on_blank, which will make " " fail the validation where it didn‘t before 1309
  • Added Errors#add_on_blank which works like Errors#add_on_empty, but uses Object#blank? instead
  • Added the :if option to all validations that can either use a block or a method pointer to determine whether the validation should be run or not. 1324 [Duane Johnson/jhosteny]. Examples:

    Conditional validations such as the following are made possible:

      validates_numericality_of :income, :if => :employed?

    Conditional validations can also solve the salted login generator problem:

      validates_confirmation_of :password, :if => :new_password?

    Using blocks:

      validates_presence_of :username, :if => Proc.new { |user| user.signup_step > 1 }
  • Fixed use of construct_finder_sql when using :join 1288 [dwlt@dwlt.net]
  • Fixed that :delete_sql in has_and_belongs_to_many associations couldn‘t access record properties 1299 [Rick Olson]
  • Fixed that clone would break when an aggregate had the same name as one of its attributes 1307 [Jeremy Kemper]
  • Changed that destroying an object will only freeze the attributes hash, which keeps the object from having attributes changed (as that wouldn‘t make sense), but allows for the querying of associations after it has been destroyed.
  • Changed the callbacks such that observers are notified before the in-object callbacks are triggered. Without this change, it wasn‘t possible to act on the whole object in something like a before_destroy observer without having the objects own callbacks (like deleting associations) called first.
  • Added option for passing an array to the find_all version of the dynamic finders and have it evaluated as an IN fragment. Example:
      # SELECT * FROM topics WHERE title IN ('First', 'Second')
  Topic.find_all_by_title(["First", "Second"])
  • Added compatibility with camelCase column names for dynamic finders 533 [Dee.Zsombor]
  • Fixed extraneous comma in count() function that made it not work with joins 1156 [jarkko/Dee.Zsombor]
  • Fixed incompatibility with Base#find with an array of ids that would fail when using eager loading 1186 [Alisdair McDiarmid]
  • Fixed that validate_length_of lost :on option when :within was specified 1195 [jhosteny@mac.com]
  • Added encoding and min_messages options for PostgreSQL 1205 [shugo]. Configuration example:
      development:
    adapter: postgresql
    database: rails_development
    host: localhost
    username: postgres
    password:
    encoding: UTF8
    min_messages: ERROR
  • Fixed acts_as_list where deleting an item that was removed from the list would ruin the positioning of other list items 1197 [Jamis Buck]
  • Added validates_exclusion_of as a negative of validates_inclusion_of
  • Optimized counting of has_many associations by setting the association to empty if the count is 0 so repeated calls doesn‘t trigger database calls

*1.10.1* (20th April, 2005)

  • Fixed frivilous database queries being triggered with eager loading on empty associations and other things
  • Fixed order of loading in eager associations
  • Fixed stray comma when using eager loading and ordering together from has_many associations 1143

*1.10.0* (19th April, 2005)

  • Added eager loading of associations as a way to solve the N+1 problem more gracefully without piggy-back queries. Example:
      for post in Post.find(:all, :limit => 100)
    puts "Post:            " + post.title
    puts "Written by:      " + post.author.name
    puts "Last comment on: " + post.comments.first.created_on
  end

    This used to generate 301 database queries if all 100 posts had both author and comments. It can now be written as:

      for post in Post.find(:all, :limit => 100, :include => [ :author, :comments ])

    …and the number of database queries needed is now 1.

  • Added new unified Base.find API and deprecated the use of find_first and find_all. See the documentation for Base.find. Examples:
      Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
  Person.find(1, 5, 6, :conditions => "administrator = 1", :order => "created_on DESC")
  Person.find(:first, :order => "created_on DESC", :offset => 5)
  Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
  Person.find(:all, :offset => 10, :limit => 10)
  • Added acts_as_nested_set 1000 [wschenk]. Introduction:
      This acts provides Nested Set functionality.  Nested Set is similiar to Tree, but with
  the added feature that you can select the children and all of it's descendants with
  a single query.  A good use case for this is a threaded post system, where you want
  to display every reply to a comment without multiple selects.
  • Added Base.save! that attempts to save the record just like Base.save but will raise a RecordInvalid exception instead of returning false if the record is not valid [After much pestering from Dave Thomas]
  • Fixed PostgreSQL usage of fixtures with regards to public schemas and table names with dots 962 [gnuman1@gmail.com]
  • Fixed that fixtures were being deleted in the same order as inserts causing FK errors 890 [andrew.john.peters@gmail.com]
  • Fixed loading of fixtures in to be in the right order (or PostgreSQL would bark) 1047 [stephenh@chase3000.com]
  • Fixed page caching for non-vhost applications living underneath the root 1004 [Ben Schumacher]
  • Fixes a problem with the SQL Adapter which was resulting in IDENTITY_INSERT not being set to ON when it should be 1104 [adelle]
  • Added the option to specify the acceptance string in validates_acceptance_of 1106 [caleb@aei-tech.com]
  • Added insert_at(position) to acts_as_list 1083 [DeLynnB]
  • Removed the default order by id on has_and_belongs_to_many queries as it could kill performance on large sets (you can still specify by hand with :order)
  • Fixed that Base.silence should restore the old logger level when done, not just set it to DEBUG 1084 [yon@milliped.com]
  • Fixed boolean saving on Oracle 1093 [mparrish@pearware.org]
  • Moved build_association and create_association for has_one and belongs_to out of deprecation as they work when the association is nil unlike association.build and association.create, which require the association to be already in place 864
  • Added rollbacks of transactions if they‘re active as the dispatcher is killed gracefully (TERM signal) 1054 [Leon Bredt]
  • Added quoting of column names for fixtures 997 [jcfischer@gmail.com]
  • Fixed counter_sql when no records exist in database for PostgreSQL (would give error, not 0) 1039 [Caleb Tennis]
  • Fixed that benchmarking times for rendering included db runtimes 987 [skaes@web.de]
  • Fixed boolean queries for t/f fields in PostgreSQL 995 [dave@cherryville.org]
  • Added that model.items.delete(child) will delete the child, not just set the foreign key to nil, if the child is dependent on the model 978 [Jeremy Kemper]
  • Fixed auto-stamping of dates (created_on/updated_on) for PostgreSQL 985 [dave@cherryville.org]
  • Fixed Base.silence/benchmark to only log if a logger has been configured 986 [skaes@web.de]
  • Added a join parameter as the third argument to Base.find_first and as the second to Base.count 426, 988 [skaes@web.de]
  • Fixed bug in Base#hash method that would treat records with the same string-based id as different [Dave Thomas]
  • Renamed DateHelper#distance_of_time_in_words_to_now to DateHelper#time_ago_in_words (old method name is still available as a deprecated alias)

*1.9.1* (27th March, 2005)

  • Fixed that Active Record objects with float attribute could not be cloned 808
  • Fixed that MissingSourceFile‘s wasn‘t properly detected in production mode 925 [Nicholas Seckar]
  • Fixed that :counter_cache option would look for a line_items_count column for a LineItem object instead of lineitems_count
  • Fixed that AR exists?() would explode on postgresql if the passed id did not match the PK type 900 [Scott Barron]
  • Fixed the MS SQL adapter to work with the new limit/offset approach and with binary data (still suffering from 7KB limit, though) 901 [delynnb]

*1.9.0* (22th March, 2005)

  • Added adapter independent limit clause as a two-element array with the first being the limit, the second being the offset 795 [Sam Stephenson]. Example:
      Developer.find_all nil, 'id ASC', 5      # return the first five developers
  Developer.find_all nil, 'id ASC', [3, 8] # return three developers, starting from #8 and forward

    This doesn‘t yet work with the DB2 or MS SQL adapters. Patches to make that happen are encouraged.

  • Added alias_method :to_param, :id to Base, such that Active Record objects to be used as URL parameters in Action Pack automatically 812 [Nicholas Seckar/Sam Stephenson]
  • Improved the performance of the OCI8 adapter for Oracle 723 [pilx/gjenkins]
  • Added type conversion before saving a record, so string-based values like "10.0" aren‘t left for the database to convert 820 [dave@cherryville.org]
  • Added with additional settings for working with transactional fixtures and pre-loaded test databases 865 [mindel]
  • Fixed acts_as_list to trigger remove_from_list on destroy after the fact, not before, so a unique position can be maintained 871 [Alisdair McDiarmid]
  • Added the possibility of specifying fixtures in multiple calls 816 [kim@tinker.com]
  • Added Base.exists?(id) that‘ll return true if an object of the class with the given id exists 854 [stian@grytoyr.net]
  • Added optionally allow for nil or empty strings with validates_numericality_of 801 [Sebastian Kanthak]
  • Fixed problem with using slashes in validates_format_of regular expressions 801 [Sebastian Kanthak]
  • Fixed that SQLite3 exceptions are caught and reported properly 823 [yerejm]
  • Added that all types of after_find/after_initialized callbacks are triggered if the explicit implementation is present, not only the explicit implementation itself
  • Fixed that symbols can be used on attribute assignment, like page.emails.create(:subject => data.subject, :body => data.body)

*1.8.0* (7th March, 2005)

  • Added ActiveRecord::Base.colorize_logging to control whether to use colors in logs or not (on by default)
  • Added support for timestamp with time zone in PostgreSQL 560 [Scott Barron]
  • Added MultiparameterAssignmentErrors and AttributeAssignmentError exceptions 777 [demetrius]. Documentation:
     * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
   +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
   objects that should be inspected to determine which attributes triggered the errors.
 * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
   You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
  • Fixed that postgresql adapter would fails when reading bytea fields with null value 771 [rodrigo k]
  • Added transactional fixtures that uses rollback to undo changes to fixtures instead of DELETE/INSERT — it‘s much faster. See documentation under Fixtures 760 [Jeremy Kemper]
  • Added destruction of dependent objects in has_one associations when a new assignment happens 742 [mindel]. Example:
      class Account < ActiveRecord::Base
    has_one :credit_card, :dependent => true
  end
  class CreditCard < ActiveRecord::Base
    belongs_to :account
  end

  account.credit_card # => returns existing credit card, lets say id = 12
  account.credit_card = CreditCard.create("number" => "123")
  account.save # => CC with id = 12 is destroyed
  • Added validates_numericality_of 716 [skanthak/c.r.mcgrath]. Docuemntation:
      Validates whether the value of the specified attribute is numeric by trying to convert it to
  a float with Kernel.Float (if <tt>integer</tt> is false) or applying it to the regular expression
  <tt>/^[\+\-]?\d+$/</tt> (if <tt>integer</tt> is set to true).

    class Person < ActiveRecord::Base
      validates_numericality_of :value, :on => :create
    end

  Configuration options:
  * <tt>message</tt> - A custom error message (default is: "is not a number")
  * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
  * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
  • Fixed that HasManyAssociation#count was using :finder_sql rather than :counter_sql if it was available 445 [Scott Barron]
  • Added better defaults for composed_of, so statements like composed_of :time_zone, :mapping => %w( time_zone time_zone ) can be written without the mapping part (it‘s now assumed)
  • Added MacroReflection#macro which will return a symbol describing the macro used (like :composed_of or :has_many) 718, 248 [james@slashetc.com]

*1.7.0* (24th February, 2005)

  • Changed the auto-timestamping feature to use ActiveRecord::Base.default_timezone instead of entertaining the parallel ActiveRecord::Base.timestamps_gmt method. The latter is now deprecated and will throw a warning on use (but still work) 710 [Jamis Buck]
  • Added a OCI8-based Oracle adapter that has been verified to work with Oracle 8 and 9 629 [Graham Jenkins]. Usage notes:
      1.  Key generation uses a sequence "rails_sequence" for all tables. (I couldn't find a simple
      and safe way of passing table-specific sequence information to the adapter.)
  2.  Oracle uses DATE or TIMESTAMP datatypes for both dates and times. Consequently I have had to
      resort to some hacks to get data converted to Date or Time in Ruby.
      If the column_name ends in _at (like created_at, updated_at) it's created as a Ruby Time. Else if the
      hours/minutes/seconds are 0, I make it a Ruby Date. Else it's a Ruby Time.
      This is nasty - but if you use Duck Typing you'll probably not care very much.
      In 9i it's tempting to map DATE to Date and TIMESTAMP to Time but I don't think that is
      valid - too many databases use DATE for both.
      Timezones and sub-second precision on timestamps are not supported.
  3.  Default values that are functions (such as "SYSDATE") are not supported. This is a
      restriction of the way active record supports default values.
  4.  Referential integrity constraints are not fully supported. Under at least
      some circumstances, active record appears to delete parent and child records out of
      sequence and out of transaction scope. (Or this may just be a problem of test setup.)

    The OCI8 driver can be retrieved from rubyforge.org/projects/ruby-oci8/

  • Added option :schema_order to the PostgreSQL adapter to support the use of multiple schemas per database 697 [YuriSchimke]
  • Optimized the SQL used to generate has_and_belongs_to_many queries by listing the join table first 693 [yerejm]
  • Fixed that when using validation macros with a custom message, if you happened to use single quotes in the message string you would get a parsing error 657 [tonka]
  • Fixed that Active Record would throw Broken Pipe errors with FCGI when the MySQL connection timed out instead of reconnecting 428 [Nicholas Seckar]
  • Added options to specify an SSL connection for MySQL. Define the following attributes in the connection config (config/database.yml in Rails) to use it: sslkey, sslcert, sslca, sslcapath, sslcipher. To use SSL with no client certs, just set :sslca = ’/dev/null’. dev.mysql.com/doc/mysql/en/secure-connections.html 604 [daniel@nightrunner.com]
  • Added automatic dropping/creating of test tables for running the unit tests on all databases 587 [adelle@bullet.net.au]
  • Fixed that find_by_* would fail when column names had numbers 670 [demetrius]
  • Fixed the SQL Server adapter on a bunch of issues 667 [DeLynn]
      1. Created a new columns method that is much cleaner.
  2. Corrected a problem with the select and select_all methods
     that didn't account for the LIMIT clause being passed into raw SQL statements.
  3. Implemented the string_to_time method in order to create proper instances of the time class.
  4. Added logic to the simplified_type method that allows the database to specify the scale of float data.
  5. Adjusted the quote_column_name to account for the fact that MS SQL is bothered by a forward slash in the data string.
  • Fixed that the dynamic finder like find_all_by_something_boolean(false) didn‘t work 649 [lmarlow@yahoo.com]
  • Added validates_each that validates each specified attribute against a block 610 [Jeremy Kemper]. Example:
      class Person < ActiveRecord::Base
    validates_each :first_name, :last_name do |record, attr|
      record.errors.add attr, 'starts with z.' if attr[0] == ?z
    end
  end
  • Added :allow_nil as an explicit option for validates_length_of, so unless that‘s set to true having the attribute as nil will also return an error if a range is specified as :within 610 [Jeremy Kemper]
  • Added that validates_* now accept blocks to perform validations 618 [Tim Bates]. Example:
      class Person < ActiveRecord::Base
    validate { |person| person.errors.add("title", "will never be valid") if SHOULD_NEVER_BE_VALID }
  end
  • Addded validation for validate all the associated objects before declaring failure with validates_associated 618 [Tim Bates]
  • Added keyword-style approach to defining the custom relational bindings 545 [Jamis Buck]. Example:
      class Project < ActiveRecord::Base
    primary_key "sysid"
    table_name "XYZ_PROJECT"
    inheritance_column { original_inheritance_column + "_id" }
  end
  • Fixed Base#clone for use with PostgreSQL 565 [hanson@surgery.wisc.edu]

*1.6.0* (January 25th, 2005)

  • Added that has_many association build and create methods can take arrays of record data like Base#create and Base#build to build/create multiple records at once.
  • Added that Base#delete and Base#destroy both can take an array of ids to delete/destroy 336
  • Added the option of supplying an array of attributes to Base#create, so that multiple records can be created at once.
  • Added the option of supplying an array of ids and attributes to Base#update, so that multiple records can be updated at once (inspired by 526/Duane Johnson). Example
      people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
  Person.update(people.keys, people.values)
  • Added ActiveRecord::Base.timestamps_gmt that can be set to true to make the automated timestamping use GMT instead of local time 520 [Scott Baron]
  • Added that update_all calls sanitize_sql on its updates argument, so stuff like MyRecord.update_all([‘time = ?’, Time.now]) works 519 [notahat]
  • Fixed that the dynamic finders didn‘t treat nil as a "IS NULL" but rather "= NULL" case 515 [Demetrius]
  • Added bind-named arrays for interpolating a group of ids or strings in conditions 528 [Jeremy Kemper]
  • Added that has_and_belongs_to_many associations with additional attributes also can be created between unsaved objects and only committed to the database when Base#save is called on the associator 524 [Eric Anderson]
  • Fixed that records fetched with piggy-back attributes or through rich has_and_belongs_to_many associations couldn‘t be saved due to the extra attributes not part of the table 522 [Eric Anderson]
  • Added mass-assignment protection for the inheritance column — regardless of a custom column is used or not
  • Fixed that association proxies would fail === tests like PremiumSubscription === @account.subscription
  • Fixed that column aliases didn‘t work as expected with the new MySql411 driver 507 [Demetrius]
  • Fixed that find_all would produce invalid sql when called sequentialy 490 [Scott Baron]

*1.5.1* (January 18th, 2005)

  • Fixed that the belongs_to and has_one proxy would fail a test like ‘if project.manager’ — this unfortunately also means that you can‘t call methods like project.manager.build unless there already is a manager on the project 492 [Tim Bates]
  • Fixed that the Ruby/MySQL adapter wouldn‘t connect if the password was empty 503 [Pelle]

*1.5.0* (January 17th, 2005)

  • Fixed that unit tests for MySQL are now run as the "rails" user instead of root 455 [Eric Hodel]
  • Added validates_associated that enables validation of objects in an unsaved association 398 [Tim Bates]. Example:
      class Book < ActiveRecord::Base
    has_many :pages
    belongs_to :library

    validates_associated :pages, :library
  end
  • Added support for associating unsaved objects 402 [Tim Bates]. Rules that govern this addition:
      == Unsaved objects and associations

  You can manipulate objects and associations before they are saved to the database, but there is some special behaviour you should be
  aware of, mostly involving the saving of associated objects.

  === One-to-one associations

  * Assigning an object to a has_one association automatically saves that object, and the object being replaced (if there is one), in
    order to update their primary keys - except if the parent object is unsaved (new_record? == true).
  * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns false and the assignment
    is cancelled.
  * If you wish to assign an object to a has_one association without saving it, use the #association.build method (documented below).
  * Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does
    not save the parent either.

  === Collections

  * Adding an object to a collection (has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object
    (the owner of the collection) is not yet stored in the database.
  * If saving any of the objects being added to a collection (via #push or similar) fails, then #push returns false.
  * You can add an object to a collection without automatically saving it by using the #collection.build method (documented below).
  * All unsaved (new_record? == true) members of the collection are automatically saved when the parent is saved.
  • Added replace to associations, so you can do project.manager.replace(new_manager) or project.milestones.replace(new_milestones) 402 [Tim Bates]
  • Added build and create methods to has_one and belongs_to associations, so you can now do project.manager.build(attributes) 402 [Tim Bates]
  • Added that if a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last. 402 [Tim Bates]
  • Fixed that Base#== wouldn‘t work for multiple references to the same unsaved object 402 [Tim Bates]
  • Fixed binary support for PostgreSQL 444 [alex@byzantine.no]
  • Added a differenciation between AssociationCollection#size and -length. Now AssociationCollection#size returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn‘t been loaded and calling collection.size if it has. If it‘s more likely than not that the collection does have a size larger than zero and you need to fetch that collection afterwards, it‘ll take one less SELECT query if you use length.
  • Added Base#attributes that returns a hash of all the attributes with their names as keys and clones of their objects as values 433 [atyp.de]
  • Fixed that foreign keys named the same as the association would cause stack overflow 437 [Eric Anderson]
  • Fixed default scope of acts_as_list from "1" to "1 = 1", so it‘ll work in PostgreSQL (among other places) 427 [Alexey]
  • Added Base#reload that reloads the attributes of an object from the database 422 [Andreas Schwarz]
  • Added SQLite3 compatibility through the sqlite3-ruby adapter by Jamis Buck 381 [Jeremy Kemper]
  • Added support for the new protocol spoken by MySQL 4.1.1+ servers for the Ruby/MySQL adapter that ships with Rails 440 [Matt Mower]
  • Added that Observers can use the observes class method instead of overwriting self.observed_class().
      Before:
    class ListSweeper < ActiveRecord::Base
      def self.observed_class() [ List, Item ]
    end

  After:
    class ListSweeper < ActiveRecord::Base
      observes List, Item
    end
  • Fixed that conditions in has_many and has_and_belongs_to_many should be interpolated just like the finder_sql is
  • Fixed Base#update_attribute to be indifferent to whether a string or symbol is used to describe the name
  • Added Base#toggle(attribute) and Base#toggle!(attribute) that makes it easier to flip a switch or flag.
      Before: topic.update_attribute(:approved, !approved?)
  After : topic.toggle!(:approved)
  • Added Base#increment!(attribute) and Base#decrement!(attribute) that also saves the records. Example:
      page.views # => 1
  page.increment!(:views) # executes an UPDATE statement
  page.views # => 2

  page.increment(:views).increment!(:views)
  page.views # => 4
  • Added Base#increment(attribute) and Base#decrement(attribute) that encapsulates the += 1 and -= 1 patterns.

*1.14.2* (April 9th, 2005)

  • Fixed calculations for the Oracle Adapter (closes 4626) [Michael Schoen]

*1.14.1* (April 6th, 2006)

  • Fix type_name_with_module to handle type names that begin with ’::’. Closes 4614. [Nicholas Seckar]
  • Fixed that that multiparameter assignment doesn‘t work with aggregations (closes 4620) [Lars Pind]
  • Enable Limit/Offset in Calculations (closes 4558) [lmarlow@yahoo.com]
  • Fixed that loading including associations returns all results if Load IDs For Limited Eager Loading returns none (closes 4528) [Rick]
  • Fixed HasManyAssociation#find bugs when :finder_sql is set 4600 [lagroue@free.fr]
  • Allow AR::Base#respond_to? to behave when @attributes is nil [zenspider]
  • Support eager includes when going through a polymorphic has_many association. [Rick]
  • Added support for eagerly including polymorphic has_one associations. (closes 4525) [Rick]
      class Post < ActiveRecord::Base
    has_one :tagging, :as => :taggable
  end

  Post.find :all, :include => :tagging
  • Added descriptive error messages for invalid has_many :through associations: going through :has_one or :has_and_belongs_to_many [Rick]
  • Added support for going through a polymorphic has_many association: (closes 4401) [Rick]
      class PhotoCollection < ActiveRecord::Base
    has_many :photos, :as => :photographic
    belongs_to :firm
  end

  class Firm < ActiveRecord::Base
    has_many :photo_collections
    has_many :photos, :through => :photo_collections
  end
  • Multiple fixes and optimizations in PostgreSQL adapter, allowing ruby-postgres gem to work properly. [ruben.nine@gmail.com]
  • Fixed that AssociationCollection#delete_all should work even if the records of the association are not loaded yet. [Florian Weber]
  • Changed those private ActiveRecord methods to take optional third argument :auto instead of nil for performance optimizations. (closes 4456) [Stefan]
  • Private ActiveRecord methods add_limit!, add_joins!, and add_conditions! take an OPTIONAL third argument ‘scope’ (closes 4456) [Rick]
  • DEPRECATED: Using additional attributes on has_and_belongs_to_many associations. Instead upgrade your association to be a real join model [DHH]
  • Fixed that records returned from has_and_belongs_to_many associations with additional attributes should be marked as read only (fixes 4512) [DHH]
  • Do not implicitly mark recordss of has_many :through as readonly but do mark habtm records as readonly (eventually only on join tables without rich attributes). [Marcel Mollina Jr.]
  • Fixed broken OCIAdapter 4457 [schoenm@earthlink.net]

*1.14.0* (March 27th, 2006)

  • Replace ‘rescue Object’ with a finer grained rescue. Closes 4431. [Nicholas Seckar]
  • Fixed eager loading so that an aliased table cannot clash with a has_and_belongs_to_many join table [Rick]
  • Add support for :include to with_scope [andrew@redlinesoftware.com]
  • Support the use of public synonyms with the Oracle adapter; required ruby-oci8 v0.1.14 4390 [schoenm@earthlink.net]
  • Change periods (.) in table aliases to _‘s. Closes 4251 [jeff@ministrycentered.com]
  • Changed has_and_belongs_to_many join to INNER JOIN for Mysql 3.23.x. Closes 4348 [Rick]
  • Fixed issue that kept :select options from being scoped [Rick]
  • Fixed db_schema_import when binary types are present 3101 [DHH]
  • Fixed that MySQL enums should always be returned as strings 3501 [DHH]
  • Change has_many :through to use the :source option to specify the source association. :class_name is now ignored. [Rick Olson]
      class Connection < ActiveRecord::Base
    belongs_to :user
    belongs_to :channel
  end

  class Channel < ActiveRecord::Base
    has_many :connections
    has_many :contacts, :through => :connections, :class_name => 'User' # OLD
    has_many :contacts, :through => :connections, :source => :user      # NEW
  end
  • Fixed DB2 adapter so nullable columns will be determines correctly now and quotes from column default values will be removed 4350 [contact@maik-schmidt.de]
  • Allow overriding of find parameters in scoped has_many :through calls [Rick Olson]

    In this example, :include => false disables the default eager association from loading. :select changes the standard select clause. :joins specifies a join that is added to the end of the has_many :through query.

      class Post < ActiveRecord::Base
    has_many :tags, :through => :taggings, :include => :tagging do
      def add_joins_and_select
        find :all, :select => 'tags.*, authors.id as author_id', :include => false,
          :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id'
      end
    end
  end
  • Fixed that schema changes while the database was open would break any connections to a SQLite database (now we reconnect if that error is throw) [DHH]
  • Don‘t classify the has_one class when eager loading, it is already singular. Add tests. (closes 4117) [jonathan@bluewire.net.nz]
  • Quit ignoring default :include options in has_many :through calls [Mark James]
  • Allow has_many :through associations to find the source association by setting a custom class (closes 4307) [jonathan@bluewire.net.nz]
  • Eager Loading support added for has_many :through => :has_many associations (see below). [Rick Olson]
  • Allow has_many :through to work on has_many associations (closes 3864) [sco@scottraymond.net] Example:
      class Firm < ActiveRecord::Base
    has_many :clients
    has_many :invoices, :through => :clients
  end

  class Client < ActiveRecord::Base
    belongs_to :firm
    has_many   :invoices
  end

  class Invoice < ActiveRecord::Base
    belongs_to :client
  end
  • Raise error when trying to select many polymorphic objects with has_many :through or :include (closes 4226) [josh@hasmanythrough.com]
  • Fixed has_many :through to include :conditions set on the :through association. closes 4020 [jonathan@bluewire.net.nz]
  • Fix that has_many :through honors the foreign key set by the belongs_to association in the join model (closes 4259) [andylien@gmail.com / Rick]
  • SQL Server adapter gets some love 4298 [rtomayko@gmail.com]
  • Added OpenBase database adapter that builds on top of the www.spice-of-life.net/ruby-openbase/ driver. All functionality except LIMIT/OFFSET is supported 3528 [derrickspell@cdmplus.com]
  • Rework table aliasing to account for truncated table aliases. Add smarter table aliasing when doing eager loading of STI associations. This allows you to use the association name in the order/where clause. [Jonathan Viney / Rick Olson] 4108 Example (SpecialComment is using STI):
      Author.find(:all, :include => { :posts => :special_comments }, :order => 'special_comments.body')
  • Add AbstractAdapter#table_alias_for to create table aliases according to the rules of the current adapter. [Rick]
  • Provide access to the underlying database connection through Adapter#raw_connection. Enables the use of db-specific methods without complicating the adapters. 2090 [Koz]
  • Remove broken attempts at handling columns with a default of ‘now()’ in the postgresql adapter. 2257 [Koz]
  • Added connection#current_database that‘ll return of the current database (only works in MySQL, SQL Server, and Oracle so far — please help implement for the rest of the adapters) 3663 [Tom ward]
  • Fixed that Migration#execute would have the table name prefix appended to its query 4110 [mark.imbriaco@pobox.com]
  • Make all tinyint(1) variants act like boolean in mysql (tinyint(1) unsigned, etc.) [Jamis Buck]
  • Use association‘s :conditions when eager loading. [jeremyevans0@gmail.com] 4144
  • Alias the has_and_belongs_to_many join table on eager includes. 4106 [jeremyevans0@gmail.com]

    This statement would normally error because the projects_developers table is joined twice, and therefore joined_on would be ambiguous.

      Developer.find(:all, :include => {:projects => :developers}, :conditions => 'join_project_developers.joined_on IS NOT NULL')
  • Oracle adapter gets some love 4230 [schoenm@earthlink.net]
      * Changes :text to CLOB rather than BLOB [Moses Hohman]
  * Fixes an issue with nil numeric length/scales (several)
  * Implements support for XMLTYPE columns [wilig / Kubo Takehiro]
  * Tweaks a unit test to get it all green again
  * Adds support for #current_database
  • Added Base.abstract_class? that marks which classes are not part of the Active Record hierarchy 3704 [Rick Olson]
      class CachedModel < ActiveRecord::Base
    self.abstract_class = true
  end

  class Post < CachedModel
  end

  CachedModel.abstract_class?
  => true

  Post.abstract_class?
  => false

  Post.base_class
  => Post

  Post.table_name
  => 'posts'
  • Allow :dependent options to be used with polymorphic joins. 3820 [Rick Olson]
      class Foo < ActiveRecord::Base
    has_many :attachments, :as => :attachable, :dependent => :delete_all
  end
  • Nicer error message on has_many :through when :through reflection can not be found. 4042 [court3nay@gmail.com]
  • Upgrade to Transaction::Simple 1.3 [Jamis Buck]
  • Catch FixtureClassNotFound when using instantiated fixtures on a fixture that has no ActiveRecord model [Rick Olson]
  • Allow ordering of calculated results and/or grouped fields in calculations [solo@gatelys.com]
  • Make ActiveRecord::Base#save! return true instead of nil on success. 4173 [johan@johansorensen.com]
  • Dynamically set allow_concurrency. 4044 [Stefan Kaes]
  • Added Base#to_xml that‘ll turn the current record into a XML representation [DHH]. Example:
      topic.to_xml

    …returns:

      <?xml version="1.0" encoding="UTF-8"?>
  <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <id type="integer">1</id>
    <approved type="boolean">false</approved>
    <replies-count type="integer">0</replies-count>
    <bonus-time type="datetime">2000-01-01 08:28:00</bonus-time>
    <written-on type="datetime">2003-07-16 09:28:00</written-on>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

    …and you can configure with:

      topic.to_xml(:skip_instruct => true, :except => [ :id, bonus_time, :written_on, replies_count ])

    …that‘ll return:

      <topic>
    <title>The First Topic</title>
    <author-name>David</author-name>
    <approved type="boolean">false</approved>
    <content>Have a nice day</content>
    <author-email-address>david@loudthinking.com</author-email-address>
    <parent-id></parent-id>
    <last-read type="date">2004-04-15</last-read>
  </topic>

    You can even do load first-level associations as part of the document:

      firm.to_xml :include => [ :account, :clients ]

    …that‘ll return something like:

      <?xml version="1.0" encoding="UTF-8"?>
  <firm>
    <id type="integer">1</id>
    <rating type="integer">1</rating>
    <name>37signals</name>
    <clients>
      <client>
        <rating type="integer">1</rating>
        <name>Summit</name>
      </client>
      <client>
        <rating type="integer">1</rating>
        <name>Microsoft</name>
      </client>
    </clients>
    <account>
      <id type="integer">1</id>
      <credit-limit type="integer">50</credit-limit>
    </account>
  </firm>
  • Allow :counter_cache to take a column name for custom counter cache columns [Jamis Buck]
  • Documentation fixes for :dependent [robby@planetargon.com]
  • Stop the MySQL adapter crashing when views are present. 3782 [Jonathan Viney]
  • Don‘t classify the belongs_to class, it is already singular 4117 [keithm@infused.org]
  • Allow set_fixture_class to take Classes instead of strings for a class in a module. Raise FixtureClassNotFound if a fixture can‘t load. [Rick Olson]
  • Fix quoting of inheritance column for STI eager loading 4098 [Jonathan Viney <jonathan@bluewire.net.nz>]
  • Added smarter table aliasing for eager associations for multiple self joins 3580 [Rick Olson]
      * The first time a table is referenced in a join, no alias is used.
  * After that, the parent class name and the reflection name are used.

      Tree.find(:all, :include => :children) # LEFT OUTER JOIN trees AS tree_children ...

  * Any additional join references get a numerical suffix like '_2', '_3', etc.
  • Fixed eager loading problems with single-table inheritance 3580 [Rick Olson]. Post.find(:all, :include => :special_comments) now returns all posts, and any special comments that the posts may have. And made STI work with has_many :through and polymorphic belongs_to.
  • Added cascading eager loading that allows for queries like Author.find(:all, :include=> { :posts=> :comments }), which will fetch all authors, their posts, and the comments belonging to those posts in a single query (using LEFT OUTER JOIN) 3913 [anna@wota.jp]. Examples:
      # cascaded in two levels
  >> Author.find(:all, :include=>{:posts=>:comments})
  => authors
       +- posts
            +- comments

  # cascaded in two levels and normal association
  >> Author.find(:all, :include=>[{:posts=>:comments}, :categorizations])
  => authors
       +- posts
            +- comments
       +- categorizations

  # cascaded in two levels with two has_many associations
  >> Author.find(:all, :include=>{:posts=>[:comments, :categorizations]})
  => authors
       +- posts
            +- comments
            +- categorizations

  # cascaded in three levels
  >> Company.find(:all, :include=>{:groups=>{:members=>{:favorites}}})
  => companies
       +- groups
            +- members
                 +- favorites
  • Make counter cache work when replacing an association 3245 [eugenol@gmail.com]
  • Make migrations verbose [Jamis Buck]
  • Make counter_cache work with polymorphic belongs_to [Jamis Buck]
  • Fixed that calling HasOneProxy#build_model repeatedly would cause saving to happen 4058 [anna@wota.jp]
  • Added Sybase database adapter that relies on the Sybase Open Client bindings (see raa.ruby-lang.org/project/sybase-ctlib) 3765 [John Sheets]. It‘s almost completely Active Record compliant (including migrations), but has the following caveats:
      * Does not support DATE SQL column types; use DATETIME instead.
  * Date columns on HABTM join tables are returned as String, not Time.
  * Insertions are potentially broken for :polymorphic join tables
  * BLOB column access not yet fully supported
  • Clear stale, cached connections left behind by defunct threads. [Jeremy Kemper]
  • CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. Most AR usage is in single-threaded applications. [Jeremy Kemper]
  • Renamed the "oci" adapter to "oracle", but kept the old name as an alias 4017 [schoenm@earthlink.net]
  • Fixed that Base.save should always return false if the save didn‘t succeed, including if it has halted by before_save‘s 1861, 2477 [DHH]
  • Speed up class -> connection caching and stale connection verification. 3979 [Stefan Kaes]
  • Add set_fixture_class to allow the use of table name accessors with models which use set_table_name. [Kevin Clark]
  • Added that fixtures to placed in subdirectories of the main fixture files are also loaded 3937 [dblack@wobblini.net]
  • Define attribute query methods to avoid method_missing calls. 3677 [jonathan@bluewire.net.nz]
  • ActiveRecord::Base.remove_connection explicitly closes database connections and doesn‘t corrupt the connection cache. Introducing the disconnect! instance method for the PostgreSQL, MySQL, and SQL Server adapters; implementations for the others are welcome. 3591 [Simon Stapleton, Tom Ward]
  • Added support for nested scopes 3407 [anna@wota.jp]. Examples:
      Developer.with_scope(:find => { :conditions => "salary > 10000", :limit => 10 }) do
    Developer.find(:all)     # => SELECT * FROM developers WHERE (salary > 10000) LIMIT 10

    # inner rule is used. (all previous parameters are ignored)
    Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
      Developer.find(:all)   # => SELECT * FROM developers WHERE (name = 'Jamis')
    end

    # parameters are merged
    Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
      Developer.find(:all)   # => SELECT * FROM developers WHERE (( salary > 10000 ) AND ( name = 'Jamis' )) LIMIT 10
    end
  end
  • Fixed db2 connection with empty user_name and auth options 3622 [phurley@gmail.com]
  • Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes 3699 [Masao Mutoh]
  • Fixed that reflections would bleed across class boundaries in single-table inheritance setups 3796 [lars@pind.com]
  • Added calculations: Base.count, Base.average, Base.sum, Base.minimum, Base.maxmium, and the generic Base.calculate. All can be used with :group and :having. Calculations and statitics need no longer require custom SQL. 3958 [Rick Olson]. Examples:
      Person.average :age
  Person.minimum :age
  Person.maximum :age
  Person.sum :salary, :group => :last_name
  • Renamed Errors#count to Errors#size but kept an alias for the old name (and included an alias for length too) 3920 [contact@lukeredpath.co.uk]
  • Reflections don‘t attempt to resolve module nesting of association classes. Simplify type computation. [Jeremy Kemper]
  • Improved the Oracle OCI Adapter with better performance for column reflection (from 3210), fixes to migrations (from 3476 and 3742), tweaks to unit tests (from 3610), and improved documentation (from 2446) 3879 [Aggregated by schoenm@earthlink.net]
  • Fixed that the schema_info table used by ActiveRecord::Schema.define should respect table pre- and suffixes 3834 [rubyonrails@atyp.de]
  • Added :select option to Base.count that‘ll allow you to select something else than * to be counted on. Especially important for count queries using DISTINCT 3839 [skaes]
  • Correct syntax error in mysql DDL, and make AAACreateTablesTest run first [Bob Silva]
  • Allow :include to be used with has_many :through associations 3611 [Michael Schoen]
  • PostgreSQL: smarter schema dumps using pk_and_sequence_for(table). 2920 [Blair Zajac]
  • SQLServer: more compatible limit/offset emulation. 3779 [Tom Ward]
  • Polymorphic join support for has_one associations (has_one :foo, :as => :bar) 3785 [Rick Olson]
  • PostgreSQL: correctly parse negative integer column defaults. 3776 [bellis@deepthought.org]
  • Fix problems with count when used with :include [Jeremy Hopple and Kevin Clark]
  • ActiveRecord::RecordInvalid now states which validations failed in its default error message [Tobias Luetke]
  • Using AssociationCollection#build with arrays of hashes should call build, not create [DHH]
  • Remove definition of reloadable? from ActiveRecord::Base to make way for new Reloadable code. [Nicholas Seckar]
  • Fixed schema handling for DB2 adapter that didn‘t work: an initial schema could be set, but it wasn‘t used when getting tables and indexes 3678 [Maik Schmidt]
  • Support the :column option for remove_index with the PostgreSQL adapter. 3661 [shugo@ruby-lang.org]
  • Add documentation for add_index and remove_index. 3600 [Manfred Stienstra <m.stienstra@fngtps.com>]
  • If the OCI library is not available, raise an exception indicating as much. 3593 [schoenm@earthlink.net]
  • Add explicit :order in finder tests as postgresql orders results differently by default. 3577. [Rick Olson]
  • Make dynamic finders honor additional passed in :conditions. 3569 [Oleg Pudeyev <pudeyo@rpi.edu>, Marcel Molina Jr.]
  • Show a meaningful error when the DB2 adapter cannot be loaded due to missing dependencies. [Nicholas Seckar]
  • Make .count work for has_many associations with multi line finder sql [schoenm@earthlink.net]
  • Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jamis Buck]
  • Allow configuration of the column used for optimistic locking [wilsonb@gmail.com]
  • Don‘t hardcode ‘id’ in acts as list. [ror@philippeapril.com]
  • Fix date errors for SQLServer in association tests. 3406 [kevin.clark@gmal.com]
  • Escape database name in MySQL adapter when creating and dropping databases. 3409 [anna@wota.jp]
  • Disambiguate table names for columns in validates_uniquness_of‘s WHERE clause. 3423 [alex.borovsky@gmail.com]
  • .with_scope imposed create parameters now bypass attr_protected [Tobias Luetke]
  • Don‘t raise an exception when there are more keys than there are named bind variables when sanitizing conditions. [Marcel Molina Jr.]
  • Multiple enhancements and adjustments to DB2 adaptor. 3377 [contact@maik-schmidt.de]
  • Sanitize scoped conditions. [Marcel Molina Jr.]
  • Added option to Base.reflection_of_all_associations to specify a specific association to scope the call. For example Base.reflection_of_all_associations(:has_many) [DHH]
  • Added ActiveRecord::SchemaDumper.ignore_tables which tells SchemaDumper which tables to ignore. Useful for tables with funky column like the ones required for tsearch2. [TobiasLuetke]
  • SchemaDumper now doesn‘t fail anymore when there are unknown column types in the schema. Instead the table is ignored and a Comment is left in the schema.rb. [TobiasLuetke]
  • Fixed that saving a model with multiple habtm associations would only save the first one. 3244 [yanowitz-rubyonrails@quantumfoam.org, Florian Weber]
  • Fix change_column to work with PostgreSQL 7.x and 8.x. 3141 [wejn@box.cz, Rick Olson, Scott Barron]
  • removed :piggyback in favor of just allowing :select on :through associations. [Tobias Luetke]
  • made method missing delegation to class methods on relation target work on :through associations. [Tobias Luetke]
  • made .find() work on :through relations. [Tobias Luetke]
  • Fix typo in association docs. 3296. [Blair Zajac]
  • 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
  • MySQL: allow encoding option for mysql.rb driver. [Jeremy Kemper]
  • Added option inheritance for find calls on has_and_belongs_to_many and has_many assosociations [DHH]. Example:
      class Post
    has_many :recent_comments, :class_name => "Comment", :limit => 10, :include => :author
  end

  post.recent_comments.find(:all) # Uses LIMIT 10 and includes authors
  post.recent_comments.find(:all, :limit => nil) # Uses no limit but include authors
  post.recent_comments.find(:all, :limit => nil, :include => nil) # Uses no limit and doesn't include authors
  • Added option to specify :group, :limit, :offset, and :select options from find on has_and_belongs_to_many and has_many assosociations [DHH]
  • MySQL: fixes for the bundled mysql.rb driver. 3160 [Justin Forder]
  • SQLServer: fix obscure optimistic locking bug. 3068 [kajism@yahoo.com]
  • SQLServer: support uniqueidentifier columns. 2930 [keithm@infused.org]
  • SQLServer: cope with tables names qualified by owner. 3067 [jeff@ministrycentered.com]
  • SQLServer: cope with columns with "desc" in the name. 1950 [Ron Lusk, Ryan Tomayko]
  • SQLServer: cope with primary keys with "select" in the name. 3057 [rdifrango@captechventures.com]
  • Oracle: active? performs a select instead of a commit. 3133 [Michael Schoen]
  • MySQL: more robust test for nullified result hashes. 3124 [Stefan Kaes]
  • Reloading an instance refreshes its aggregations as well as its associations. 3024 [FranÃ§ois Beausolei]
  • Fixed that using :include together with :conditions array in Base.find would cause NoMethodError 2887 [Paul Hammmond]
  • PostgreSQL: more robust sequence name discovery. 3087 [Rick Olson]
  • Oracle: use syntax compatible with Oracle 8. 3131 [Michael Schoen]
  • MySQL: work around ruby-mysql/mysql-ruby inconsistency with mysql.stat. Eliminate usage of mysql.ping because it doesn‘t guarantee reconnect. Explicitly close and reopen the connection instead. [Jeremy Kemper]
  • Added preliminary support for polymorphic associations [DHH]
  • Added preliminary support for join models [DHH]
  • Allow validate_uniqueness_of to be scoped by more than just one column. 1559. [jeremy@jthopple.com, Marcel Molina Jr.]
  • Firebird: active? and reconnect! methods for handling stale connections. 428 [Ken Kunz <kennethkunz@gmail.com>]
  • Firebird: updated for FireRuby 0.4.0. 3009 [Ken Kunz <kennethkunz@gmail.com>]
  • MySQL and PostgreSQL: active? compatibility with the pure-Ruby driver. 428 [Jeremy Kemper]
  • Oracle: active? check pings the database rather than testing the last command status. 428 [Michael Schoen]
  • SQLServer: resolve column aliasing/quoting collision when using limit or offset in an eager find. 2974 [kajism@yahoo.com]
  • Reloading a model doesn‘t lose track of its connection. 2996 [junk@miriamtech.com, Jeremy Kemper]
  • Fixed bug where using update_attribute after pushing a record to a habtm association of the object caused duplicate rows in the join table. 2888 [colman@rominato.com, Florian Weber, Michael Schoen]
  • MySQL, PostgreSQL: reconnect! also reconfigures the connection. Otherwise, the connection ‘loses’ its settings if it times out and is reconnected. 2978 [Shugo Maeda]
  • has_and_belongs_to_many: use JOIN instead of LEFT JOIN. [Jeremy Kemper]
  • MySQL: introduce :encoding option to specify the character set for client, connection, and results. Only available for MySQL 4.1 and later with the mysql-ruby driver. Do SHOW CHARACTER SET in mysql client to see available encodings. 2975 [Shugo Maeda]
  • Add tasks to create, drop and rebuild the MySQL and PostgreSQL test databases. [Marcel Molina Jr.]
  • Correct boolean handling in generated reader methods. 2945 [don.park@gmail.com, Stefan Kaes]
  • Don‘t generate read methods for columns whose names are not valid ruby method names. 2946 [Stefan Kaes]
  • Document :force option to create_table. 2921 [Blair Zajac <blair@orcaware.com>]
  • Don‘t add the same conditions twice in has_one finder sql. 2916 [Jeremy Evans]
  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]
  • Introducing the Firebird adapter. Quote columns and use attribute_condition more consistently. Setup guide: wiki.rubyonrails.com/rails/pages/Firebird+Adapter 1874 [Ken Kunz <kennethkunz@gmail.com>]
  • SQLServer: active? and reconnect! methods for handling stale connections. 428 [kajism@yahoo.com, Tom Ward <tom@popdog.net>]
  • Associations handle case-equality more consistently: item.parts.is_a?(Array) and item.parts === Array. 1345 [MarkusQ@reality.com]
  • SQLServer: insert uses given primary key value if not nil rather than SELECT @@IDENTITY. 2866 [kajism@yahoo.com, Tom Ward <tom@popdog.net>]
  • Oracle: active? and reconnect! methods for handling stale connections. Optionally retry queries after reconnect. 428 [Michael Schoen <schoenm@earthlink.net>]
  • Correct documentation for Base.delete_all. 1568 [Newhydra]
  • Oracle: test case for column default parsing. 2788 [Michael Schoen <schoenm@earthlink.net>]
  • Update documentation for Migrations. 2861 [Tom Werner <tom@cube6media.com>]
  • When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL, MySQL, and SQLite. Make certain that all statements which may need reconnection are performed within a logged block: for example, this means no avoiding log(sql, name) { } if @logger.nil? 428 [Jeremy Kemper]
  • Oracle: Much faster column reflection. 2848 [Michael Schoen <schoenm@earthlink.net>]
  • Base.reset_sequence_name analogous to reset_table_name (mostly useful for testing). Base.define_attr_method allows nil values. [Jeremy Kemper]
  • PostgreSQL: smarter sequence name defaults, stricter last_insert_id, warn on pk without sequence. [Jeremy Kemper]
  • PostgreSQL: correctly discover custom primary key sequences. 2594 [Blair Zajac <blair@orcaware.com>, meadow.nnick@gmail.com, Jeremy Kemper]
  • SQLServer: don‘t report limits for unsupported field types. 2835 [Ryan Tomayko]
  • Include the Enumerable module in ActiveRecord::Errors. [Rick Bradley <rick@rickbradley.com>]
  • Add :group option, correspond to GROUP BY, to the find method and to the has_many association. 2818 [rubyonrails@atyp.de]
  • Don‘t cast nil or empty strings to a dummy date. 2789 [Rick Bradley <rick@rickbradley.com>]
  • acts_as_list plays nicely with inheritance by remembering the class which declared it. 2811 [rephorm@rephorm.com]
  • Fix sqlite adaptor‘s detection of missing dbfile or database declaration. [Nicholas Seckar]
  • Fixed acts_as_list for definitions without an explicit :order 2803 [jonathan@bluewire.net.nz]
  • Upgrade bundled ruby-mysql 0.2.4 with mysql411 shim (see 440) to ruby-mysql 0.2.6 with a patchset for 4.1 protocol support. Local change [301] is now a part of the main driver; reapplied local change [2182]. Removed GC.start from Result.free. [tommy@tmtm.org, akuroda@gmail.com, Doug Fales <doug.fales@gmail.com>, Jeremy Kemper]
  • Correct handling of complex order clauses with SQL Server limit emulation. 2770 [Tom Ward <tom@popdog.net>, Matt B.]
  • Correct whitespace problem in Oracle default column value parsing. 2788 [rick@rickbradley.com]
  • Destroy associated has_and_belongs_to_many records after all before_destroy callbacks but before destroy. This allows you to act on the habtm association as you please while preserving referential integrity. 2065 [larrywilliams1@gmail.com, sam.kirchmeier@gmail.com, elliot@townx.org, Jeremy Kemper]
  • Deprecate the old, confusing :exclusively_dependent option in favor of :dependent => :delete_all. [Jeremy Kemper]
  • More compatible Oracle column reflection. 2771 [Ryan Davis <ryand-ruby@zenspider.com>, Michael Schoen <schoenm@earthlink.net>]

*1.13.0* (November 7th, 2005)

  • Fixed faulty regex in get_table_name method (SQLServerAdapter) 2639 [Ryan Tomayko]
  • Added :include as an option for association declarations [DHH]. Example:
      has_many :posts, :include => [ :author, :comments ]
  • Rename Base.constrain to Base.with_scope so it doesn‘t conflict with existing concept of database constraints. Make scoping more robust: uniform method => parameters, validated method names and supported finder parameters, raise exception on nested scopes. [Jeremy Kemper] Example:
      Comment.with_scope(:find => { :conditions => 'active=true' }, :create => { :post_id => 5 }) do
    # Find where name = ? and active=true
    Comment.find :all, :conditions => ['name = ?', name]
    # Create comment associated with :post_id
    Comment.create :body => "Hello world"
  end
  • Fixed that SQL Server should ignore :size declarations on anything but integer and string in the agnostic schema representation 2756 [Ryan Tomayko]
  • Added constrain scoping for creates using a hash of attributes bound to the :creation key [DHH]. Example:
      Comment.constrain(:creation => { :post_id => 5 }) do
    # Associated with :post_id
    Comment.create :body => "Hello world"
  end

    This is rarely used directly, but allows for find_or_create on associations. So you can do:

      # If the tag doesn't exist, a new one is created that's associated with the person
  person.tags.find_or_create_by_name("Summer")
  • Added find_or_create_by_X as a second type of dynamic finder that‘ll create the record if it doesn‘t already exist [DHH]. Example:
      # No 'Summer' tag exists
  Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")

  # Now the 'Summer' tag does exist
  Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
  • Added extension capabilities to has_many and has_and_belongs_to_many proxies [DHH]. Example:
      class Account < ActiveRecord::Base
    has_many :people do
      def find_or_create_by_name(name)
        first_name, *last_name = name.split
        last_name = last_name.join " "

        find_or_create_by_first_name_and_last_name(first_name, last_name)
      end
    end
  end

  person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson")
  person.first_name # => "David"
  person.last_name  # => "Heinemeier Hansson"

    Note that the anoymous module must be declared using brackets, not do/end (due to order of evaluation).

  • Omit internal dtproperties table from SQLServer table list. 2729 [rtomayko@gmail.com]
  • Quote column names in generated SQL. 2728 [rtomayko@gmail.com]
  • Correct the pure-Ruby MySQL 4.1.1 shim‘s version test. 2718 [Jeremy Kemper]
  • Add Model.create! to match existing model.save! method. When save! raises RecordInvalid, you can catch the exception, retrieve the invalid record (invalid_exception.record), and see its errors (invalid_exception.record.errors). [Jeremy Kemper]
  • Correct fixture behavior when table name pluralization is off. 2719 [Rick Bradley <rick@rickbradley.com>]
  • Changed :dbfile to :database for SQLite adapter for consistency (old key still works as an alias) 2644 [Dan Peterson]
  • Added migration support for Oracle 2647 [Michael Schoen]
  • Worked around that connection can‘t be reset if allow_concurrency is off. 2648 [Michael Schoen <schoenm@earthlink.net>]
  • Fixed SQL Server adapter to pass even more tests and do even better 2634 [rtomayko@gmail.com]
  • Fixed SQL Server adapter so it honors options[:conditions] when applying :limits 1978 [Tom Ward]
  • Added migration support to SQL Server adapter (please someone do the same for Oracle and DB2) 2625 [Tom Ward]
  • Use AR::Base.silence rather than AR::Base.logger.silence in fixtures to preserve Log4r compatibility. 2618 [dansketcher@gmail.com]
  • Constraints are cloned so they can‘t be inadvertently modified while they‘re

in effect. Added :readonly finder constraint. Calling an association collection‘s class method (Part.foobar via item.parts.foobar) constrains :readonly => false since the collection‘s :joins constraint would otherwise force it to true. [Jeremy Kemper <rails@bitsweat.net>]

  • Added :offset and :limit to the kinds of options that Base.constrain can use 2466 [duane.johnson@gmail.com]
  • Fixed handling of nil number columns on Oracle and cleaned up tests for Oracle in general 2555 [schoenm@earthlink.net]
  • Added quoted_true and quoted_false methods and tables to db2_adapter and cleaned up tests for DB2 2493, 2624 [maik schmidt]

*1.12.2* (October 26th, 2005)

  • Allow symbols to rename columns when using SQLite adapter. 2531 [kevin.clark@gmail.com]
  • Map Active Record time to SQL TIME. 2575, 2576 [Robby Russell <robby@planetargon.com>]
  • Clarify semantics of ActiveRecord::Base#respond_to? 2560 [skaes@web.de]
  • Fixed Association#clear for associations which have not yet been accessed. 2524 [Patrick Lenz <patrick@lenz.sh>]
  • HABTM finders shouldn‘t return readonly records. 2525 [Patrick Lenz <patrick@lenz.sh>]
  • Make all tests runnable on their own. 2521. [Blair Zajac <blair@orcaware.com>]

*1.12.1* (October 19th, 2005)

  • Always parenthesize :conditions options so they may be safely combined with STI and constraints.
  • Correct PostgreSQL primary key sequence detection. 2507 [tmornini@infomania.com]
  • Added support for using limits in eager loads that involve has_many and has_and_belongs_to_many associations

*1.12.0* (October 16th, 2005)

  • Update/clean up documentation (rdoc)
  • PostgreSQL sequence support. Use set_sequence_name in your model class to specify its primary key sequence. 2292 [Rick Olson <technoweenie@gmail.com>, Robby Russell <robby@planetargon.com>]
  • Change default logging colors to work on both white and black backgrounds. [Sam Stephenson]
  • YAML fixtures support ordered hashes for fixtures with foreign key dependencies in the same table. 1896 [purestorm@ggnore.net]
  • :dependent now accepts :nullify option. Sets the foreign key of the related objects to NULL instead of deleting them. 2015 [Robby Russell <robby@planetargon.com>]
  • Introduce read-only records. If you call object.readonly! then it will mark the object as read-only and raise ReadOnlyRecord if you call object.save. object.readonly? reports whether the object is read-only. Passing :readonly => true to any finder method will mark returned records as read-only. The :joins option now implies :readonly, so if you use this option, saving the same record will now fail. Use find_by_sql to work around.
  • Avoid memleak in dev mode when using fcgi
  • Simplified .clear on active record associations by using the existing delete_records method. 1906 [Caleb <me@cpb.ca>]
  • Delegate access to a customized primary key to the conventional id method. 2444. [Blair Zajac <blair@orcaware.com>]
  • Fix errors caused by assigning a has-one or belongs-to property to itself
  • Add ActiveRecord::Base.schema_format setting which specifies how databases should be dumped [Sam Stephenson]
  • Update DB2 adapter. 2206. [contact@maik-schmidt.de]
  • Corrections to SQLServer native data types. 2267. [rails.20.clarry@spamgourmet.com]
  • Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveRecord::Base.allow_concurrency.
  • Protect id attribute from mass assigment even when the primary key is set to something else. 2438. [Blair Zajac <blair@orcaware.com>]
  • Misc doc fixes (typos/grammar/etc.). 2430. [coffee2code]
  • Add test coverage for content_columns. 2432. [coffee2code]
  • Speed up for unthreaded environments. 2431. [skaes@web.de]
  • Optimization for Mysql selects using mysql-ruby extension greater than 2.6.3. 2426. [skaes@web.de]
  • Speed up the setting of table_name. 2428. [skaes@web.de]
  • Optimize instantiation of STI subclass records. In partial fullfilment of 1236. [skaes@web.de]
  • Fix typo of ‘constrains’ to ‘contraints’. 2069. [Michael Schuerig <michael@schuerig.de>]
  • Optimization refactoring for add_limit_offset!. In partial fullfilment of 1236. [skaes@web.de]
  • Add ability to get all siblings, including the current child, with acts_as_tree. Recloses 2140. [Michael Schuerig <michael@schuerig.de>]
  • Add geometric type for postgresql adapter. 2233 [akaspick@gmail.com]
  • Add option (true by default) to generate reader methods for each attribute of a record to avoid the overhead of calling method missing. In partial fullfilment of 1236. [skaes@web.de]
  • Add convenience predicate methods on Column class. In partial fullfilment of 1236. [skaes@web.de]
  • Raise errors when invalid hash keys are passed to ActiveRecord::Base.find. 2363 [Chad Fowler <chad@chadfowler.com>, Nicholas Seckar]
  • Added :force option to create_table that‘ll try to drop the table if it already exists before creating
  • Fix transactions so that calling return while inside a transaction will not leave an open transaction on the connection. [Nicholas Seckar]
  • Use foreign_key inflection uniformly. 2156 [Blair Zajac <blair@orcaware.com>]
  • model.association.clear should destroy associated objects if :dependent => true instead of nullifying their foreign keys. 2221 [joergd@pobox.com, ObieFernandez <obiefernandez@gmail.com>]
  • Returning false from before_destroy should cancel the action. 1829 [Jeremy Huffman]
  • Recognize PostgreSQL NOW() default as equivalent to CURRENT_TIMESTAMP or CURRENT_DATE, depending on the column‘s type. 2256 [mat <mat@absolight.fr>]
  • Extensive documentation for the abstract database adapter. 2250 [François Beausoleil <fbeausoleil@ftml.net>]
  • Clean up Fixtures.reset_sequences for PostgreSQL. Handle tables with no rows and models with custom primary keys. 2174, 2183 [jay@jay.fm, Blair Zajac <blair@orcaware.com>]
  • Improve error message when nil is assigned to an attr which validates_size_of within a range. 2022 [Manuel Holtgrewe <purestorm@ggnore.net>]
  • Make update_attribute use the same writer method that update_attributes uses.
 #2237 [trevor@protocool.com]
  • Make migrations honor table name prefixes and suffixes. 2298 [Jakob S, Marcel Molina]
  • Correct and optimize PostgreSQL bytea escaping. 1745, 1837 [dave@cherryville.org, ken@miriamtech.com, bellis@deepthought.org]
  • Fixtures should only reset a PostgreSQL sequence if it corresponds to an integer primary key named id. 1749 [chris@chrisbrinker.com]
  • Standardize the interpretation of boolean columns in the Mysql and Sqlite adapters. (Use MysqlAdapter.emulate_booleans = false to disable this behavior)
  • Added new symbol-driven approach to activating observers with Base#observers= [DHH]. Example:
      ActiveRecord::Base.observers = :cacher, :garbage_collector
  • Added AbstractAdapter#select_value and AbstractAdapter#select_values as convenience methods for selecting single values, instead of hashes, of the first column in a SELECT 2283 [solo@gatelys.com]
  • Wrap :conditions in parentheses to prevent problems with OR‘s 1871 [Jamis Buck]
  • Allow the postgresql adapter to work with the SchemaDumper. [Jamis Buck]
  • Add ActiveRecord::SchemaDumper for dumping a DB schema to a pure-ruby file, making it easier to consolidate large migration lists and port database schemas between databases. [Jamis Buck]
  • Fixed migrations for Windows when using more than 10 [David Naseby]
  • Fixed that the create_x method from belongs_to wouldn‘t save the association properly 2042 [Florian Weber]
  • Fixed saving a record with two unsaved belongs_to associations pointing to the same object 2023 [Tobias Luetke]
  • Improved migrations’ behavior when the schema_info table is empty. [Nicholas Seckar]
  • Fixed that Observers didn‘t observe sub-classes 627 [Florian Weber]
  • Fix eager loading error messages, allow :include to specify tables using strings or symbols. Closes 2222 [Marcel Molina]
  • Added check for RAILS_CONNECTION_ADAPTERS on startup and only load the connection adapters specified within if its present (available in Rails through config.connection_adapters using the new config) 1958 [skae]
  • Fixed various problems with has_and_belongs_to_many when using customer finder_sql 2094 [Florian Weber]
  • Added better exception error when unknown column types are used with migrations 1814 [fbeausoleil@ftml.net]
  • Fixed "connection lost" issue with the bundled Ruby/MySQL driver (would kill the app after 8 hours of inactivity) 2163, 428 [kajism@yahoo.com]
  • Fixed comparison of Active Record objects so two new objects are not equal 2099 [deberg]
  • Fixed that the SQL Server adapter would sometimes return DBI::Timestamp objects instead of Time 2127 [Tom Ward]
  • Added the instance methods root and ancestors on acts_as_tree and fixed siblings to not include the current node 2142, 2140 [coffee2code]
  • Fixed that Active Record would call SHOW FIELDS twice (or more) for the same model when the cached results were available 1947 [sd@notso.net]
  • Added log_level and use_silence parameter to ActiveRecord::Base.benchmark. The first controls at what level the benchmark statement will be logged (now as debug, instead of info) and the second that can be passed false to include all logging statements during the benchmark block/
  • Make sure the schema_info table is created before querying the current version 1903
  • Fixtures ignore table name prefix and suffix 1987 [Jakob S]
  • Add documentation for index_type argument to add_index method for migrations 2005 [blaine@odeo.com]
  • Modify read_attribute to allow a symbol argument 2024 [Ken Kunz]
  • Make destroy return self 1913 [sebastian.kanthak@muehlheim.de]
  • Fix typo in validations documentation 1938 [court3nay]
  • Make acts_as_list work for insert_at(1) 1966 [hensleyl@papermountain.org]
  • Fix typo in count_by_sql documentation 1969 [Alexey Verkhovsky]
  • Allow add_column and create_table to specify NOT NULL 1712 [emptysands@gmail.com]
  • Fix create_table so that id column is implicitly added [Rick Olson]
  • Default sequence names for Oracle changed to #{table_name}_seq, which is the most commonly used standard. In addition, a new method ActiveRecord::Base#set_sequence_name allows the developer to set the sequence name per model. This is a non-backwards-compatible change — anyone using the old-style "rails_sequence" will need to either create new sequences, or set: ActiveRecord::Base.set_sequence_name = "rails_sequence" 1798
  • OCIAdapter now properly handles synonyms, which are commonly used to separate out the schema owner from the application user 1798
  • Fixed the handling of camelCase columns names in Oracle 1798
  • Implemented for OCI the Rakefile tasks of :clone_structure_to_test, :db_structure_dump, and :purge_test_database, which enable Oracle folks to enjoy all the agile goodness of Rails for testing. Note that the current implementation is fairly limited — only tables and sequences are cloned, not constraints or indexes. A full clone in Oracle generally requires some manual effort, and is version-specific. Post 9i, Oracle recommends the use of the DBMS_METADATA package, though that approach requires editing of the physical characteristics generated 1798
  • Fixed the handling of multiple blob columns in Oracle if one or more of them are null 1798
  • Added support for calling constrained class methods on has_many and has_and_belongs_to_many collections 1764 [Tobias Luetke]
      class Comment < AR:B
    def self.search(q)
      find(:all, :conditions => ["body = ?", q])
    end
  end

  class Post < AR:B
    has_many :comments
  end

  Post.find(1).comments.search('hi') # => SELECT * from comments WHERE post_id = 1 AND body = 'hi'

    NOTICE: This patch changes the underlying SQL generated by has_and_belongs_to_many queries. If your relying on that, such as by explicitly referencing the old t and j aliases, you‘ll need to update your code. Of course, you _shouldn‘t_ be relying on details like that no less than you should be diving in to touch private variables. But just in case you do, consider yourself noticed :)

  • Added migration support for SQLite (using temporary tables to simulate ALTER TABLE) 1771 [Sam Stephenson]
  • Remove extra definition of supports_migrations? from abstract_adaptor.rb [Nicholas Seckar]
  • Fix acts_as_list so that moving next-to-last item to the bottom does not result in duplicate item positions
  • Fixed incompatibility in DB2 adapter with the new limit/offset approach 1718 [Maik Schmidt]
  • Added :select option to find which can specify a different value than the default *, like find(:all, :select => "first_name, last_name"), if you either only want to select part of the columns or exclude columns otherwise included from a join 1338 [Stefan Kaes]

*1.11.1* (11 July, 2005)

  • Added support for limit and offset with eager loading of has_one and belongs_to associations. Using the options with has_many and has_and_belongs_to_many associations will now raise an ActiveRecord::ConfigurationError 1692 [Rick Olsen]
  • Fixed that assume_bottom_position (in acts_as_list) could be called on items already last in the list and they would move one position away from the list 1648 [tyler@kianta.com]
  • Added ActiveRecord::Base.threaded_connections flag to turn off 1-connection per thread (required for thread safety). By default it‘s on, but WEBrick in Rails need it off 1685 [Sam Stephenson]
  • Correct reflected table name for singular associations. 1688 [court3nay@gmail.com]
  • Fixed optimistic locking with SQL Server 1660 [tom@popdog.net]
  • Added ActiveRecord::Migrator.migrate that can figure out whether to go up or down based on the target version and the current
  • Added better error message for "packets out of order" 1630 [courtenay]
  • Fixed first run of "rake migrate" on PostgreSQL by not expecting a return value on the id 1640

*1.11.0* (6 July, 2005)

  • Fixed that Yaml error message in fixtures hid the real error 1623 [Nicholas Seckar]
  • Changed logging of SQL statements to use the DEBUG level instead of INFO
  • Added new Migrations framework for describing schema transformations in a way that can be easily applied across multiple databases 1604 [Tobias Luetke] See documentation under ActiveRecord::Migration and the additional support in the Rails rakefile/generator.
  • Added callback hooks to association collections 1549 [Florian Weber]. Example:
      class Project
    has_and_belongs_to_many :developers, :before_add => :evaluate_velocity

    def evaluate_velocity(developer)
      ...
    end
  end

    ..raising an exception will cause the object not to be added (or removed, with before_remove).

  • Fixed Base.content_columns call for SQL Server adapter 1450 [DeLynn Berry]
  • Fixed Base#write_attribute to work with both symbols and strings 1190 [Paul Legato]
  • Fixed that has_and_belongs_to_many didn‘t respect single table inheritance types 1081 [Florian Weber]
  • Speed up ActiveRecord#method_missing for the common case (read_attribute).
  • Only notify observers on after_find and after_initialize if these methods are defined on the model. 1235 [skaes@web.de]
  • Fixed that single-table inheritance sub-classes couldn‘t be used to limit the result set with eager loading 1215 [Chris McGrath]
  • Fixed validates_numericality_of to work with overrided getter-method when :allow_nil is on 1316 [raidel@onemail.at]
  • Added roots, root, and siblings to the batch of methods added by acts_as_tree 1541 [michael@schuerig.de]
  • Added support for limit/offset with the MS SQL Server driver so that pagination will now work 1569 [DeLynn Berry]
  • Added support for ODBC connections to MS SQL Server so you can connect from a non-Windows machine 1569 [Mark Imbriaco/DeLynn Berry]
  • Fixed that multiparameter posts ignored attr_protected 1532 [alec+rails@veryclever.net]
  • Fixed problem with eager loading when using a has_and_belongs_to_many association using :association_foreign_key 1504 [flash@vanklinkenbergsoftware.nl]
  • Fixed Base#find to honor the documentation on how :joins work and make them consistent with Base#count 1405 [pritchie@gmail.com]. What used to be:
      Developer.find :all, :joins => 'developers_projects', :conditions => 'id=developer_id AND project_id=1'

    …should instead be:

      Developer.find(
    :all,
    :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
    :conditions => 'project_id=1'
  )
  • Fixed that validations didn‘t respecting custom setting for too_short, too_long messages 1437 [Marcel Molina]
  • Fixed that clear_association_cache doesn‘t delete new associations on new records (so you can safely place new records in the session with Action Pack without having new associations wiped) 1494 [cluon]
  • Fixed that calling Model.find([]) returns [] and doesn‘t throw an exception 1379
  • Fixed that adding a record to a has_and_belongs_to collection would always save it — now it only saves if its a new record 1203 [Alisdair McDiarmid]
  • Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save — that way you can add new associations in after_create/after_update callbacks without getting them saved twice
  • Allow any Enumerable, not just Array, to work as bind variables 1344 [Jeremy Kemper]
  • Added actual database-changing behavior to collection assigment for has_many and has_and_belongs_to_many 1425 [Sebastian Kanthak]. Example:
      david.projects = [Project.find(1), Project.new("name" => "ActionWebSearch")]
  david.save

    If david.projects already contain the project with ID 1, this is left unchanged. Any other projects are dropped. And the new project is saved when david.save is called.

    Also included is a way to do assignments through IDs, which is perfect for checkbox updating, so you get to do:

      david.project_ids = [1, 5, 7]
  • Corrected typo in find SQL for has_and_belongs_to_many. 1312 [ben@bensinclair.com]
  • Fixed sanitized conditions for has_many finder method. 1281 [jackc@hylesanderson.com, pragdave, Tobias Luetke]
  • Comprehensive PostgreSQL schema support. Use the optional schema_search_path directive in database.yml to give a comma-separated list of schemas to search for your tables. This allows you, for example, to have tables in a shared schema without having to use a custom table name. See www.postgresql.org/docs/8.0/interactive/ddl-schemas.html to learn more. 827 [dave@cherryville.org]
  • Corrected @@configurations typo 1410 [david@ruppconsulting.com]
  • Return PostgreSQL columns in the order they were declared 1374 [perlguy@gmail.com]
  • Allow before/after update hooks to work on models using optimistic locking
  • Eager loading of dependent has_one associations won‘t delete the association 1212
  • Added a second parameter to the build and create method for has_one that controls whether the existing association should be replaced (which means nullifying its foreign key as well). By default this is true, but false can be passed to prevent it.
  • Using transactional fixtures now causes the data to be loaded only once.
  • Added fixture accessor methods that can be used when instantiated fixtures are disabled.
      fixtures :web_sites

  def test_something
    assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
  end
  • Added DoubleRenderError exception that‘ll be raised if render* is called twice 518 [Nicholas Seckar]
  • Fixed exceptions occuring after render has been called 1096 [Nicholas Seckar]
  • CHANGED: validates_presence_of now uses Errors#add_on_blank, which will make " " fail the validation where it didn‘t before 1309
  • Added Errors#add_on_blank which works like Errors#add_on_empty, but uses Object#blank? instead
  • Added the :if option to all validations that can either use a block or a method pointer to determine whether the validation should be run or not. 1324 [Duane Johnson/jhosteny]. Examples:

    Conditional validations such as the following are made possible:

      validates_numericality_of :income, :if => :employed?

    Conditional validations can also solve the salted login generator problem:

      validates_confirmation_of :password, :if => :new_password?

    Using blocks:

      validates_presence_of :username, :if => Proc.new { |user| user.signup_step > 1 }
  • Fixed use of construct_finder_sql when using :join 1288 [dwlt@dwlt.net]
  • Fixed that :delete_sql in has_and_belongs_to_many associations couldn‘t access record properties 1299 [Rick Olson]
  • Fixed that clone would break when an aggregate had the same name as one of its attributes 1307 [Jeremy Kemper]
  • Changed that destroying an object will only freeze the attributes hash, which keeps the object from having attributes changed (as that wouldn‘t make sense), but allows for the querying of associations after it has been destroyed.
  • Changed the callbacks such that observers are notified before the in-object callbacks are triggered. Without this change, it wasn‘t possible to act on the whole object in something like a before_destroy observer without having the objects own callbacks (like deleting associations) called first.
  • Added option for passing an array to the find_all version of the dynamic finders and have it evaluated as an IN fragment. Example:
      # SELECT * FROM topics WHERE title IN ('First', 'Second')
  Topic.find_all_by_title(["First", "Second"])
  • Added compatibility with camelCase column names for dynamic finders 533 [Dee.Zsombor]
  • Fixed extraneous comma in count() function that made it not work with joins 1156 [jarkko/Dee.Zsombor]
  • Fixed incompatibility with Base#find with an array of ids that would fail when using eager loading 1186 [Alisdair McDiarmid]
  • Fixed that validate_length_of lost :on option when :within was specified 1195 [jhosteny@mac.com]
  • Added encoding and min_messages options for PostgreSQL 1205 [shugo]. Configuration example:
      development:
    adapter: postgresql
    database: rails_development
    host: localhost
    username: postgres
    password:
    encoding: UTF8
    min_messages: ERROR
  • Fixed acts_as_list where deleting an item that was removed from the list would ruin the positioning of other list items 1197 [Jamis Buck]
  • Added validates_exclusion_of as a negative of validates_inclusion_of
  • Optimized counting of has_many associations by setting the association to empty if the count is 0 so repeated calls doesn‘t trigger database calls

*1.10.1* (20th April, 2005)

  • Fixed frivilous database queries being triggered with eager loading on empty associations and other things
  • Fixed order of loading in eager associations
  • Fixed stray comma when using eager loading and ordering together from has_many associations 1143

*1.10.0* (19th April, 2005)

  • Added eager loading of associations as a way to solve the N+1 problem more gracefully without piggy-back queries. Example:
      for post in Post.find(:all, :limit => 100)
    puts "Post:            " + post.title
    puts "Written by:      " + post.author.name
    puts "Last comment on: " + post.comments.first.created_on
  end

    This used to generate 301 database queries if all 100 posts had both author and comments. It can now be written as:

      for post in Post.find(:all, :limit => 100, :include => [ :author, :comments ])

    …and the number of database queries needed is now 1.

  • Added new unified Base.find API and deprecated the use of find_first and find_all. See the documentation for Base.find. Examples:
      Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
  Person.find(1, 5, 6, :conditions => "administrator = 1", :order => "created_on DESC")
  Person.find(:first, :order => "created_on DESC", :offset => 5)
  Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
  Person.find(:all, :offset => 10, :limit => 10)
  • Added acts_as_nested_set 1000 [wschenk]. Introduction:
      This acts provides Nested Set functionality.  Nested Set is similiar to Tree, but with
  the added feature that you can select the children and all of it's descendants with
  a single query.  A good use case for this is a threaded post system, where you want
  to display every reply to a comment without multiple selects.
  • Added Base.save! that attempts to save the record just like Base.save but will raise a RecordInvalid exception instead of returning false if the record is not valid [After much pestering from Dave Thomas]
  • Fixed PostgreSQL usage of fixtures with regards to public schemas and table names with dots 962 [gnuman1@gmail.com]
  • Fixed that fixtures were being deleted in the same order as inserts causing FK errors 890 [andrew.john.peters@gmail.com]
  • Fixed loading of fixtures in to be in the right order (or PostgreSQL would bark) 1047 [stephenh@chase3000.com]
  • Fixed page caching for non-vhost applications living underneath the root 1004 [Ben Schumacher]
  • Fixes a problem with the SQL Adapter which was resulting in IDENTITY_INSERT not being set to ON when it should be 1104 [adelle]
  • Added the option to specify the acceptance string in validates_acceptance_of 1106 [caleb@aei-tech.com]
  • Added insert_at(position) to acts_as_list 1083 [DeLynnB]
  • Removed the default order by id on has_and_belongs_to_many queries as it could kill performance on large sets (you can still specify by hand with :order)
  • Fixed that Base.silence should restore the old logger level when done, not just set it to DEBUG 1084 [yon@milliped.com]
  • Fixed boolean saving on Oracle 1093 [mparrish@pearware.org]
  • Moved build_association and create_association for has_one and belongs_to out of deprecation as they work when the association is nil unlike association.build and association.create, which require the association to be already in place 864
  • Added rollbacks of transactions if they‘re active as the dispatcher is killed gracefully (TERM signal) 1054 [Leon Bredt]
  • Added quoting of column names for fixtures 997 [jcfischer@gmail.com]
  • Fixed counter_sql when no records exist in database for PostgreSQL (would give error, not 0) 1039 [Caleb Tennis]
  • Fixed that benchmarking times for rendering included db runtimes 987 [skaes@web.de]
  • Fixed boolean queries for t/f fields in PostgreSQL 995 [dave@cherryville.org]
  • Added that model.items.delete(child) will delete the child, not just set the foreign key to nil, if the child is dependent on the model 978 [Jeremy Kemper]
  • Fixed auto-stamping of dates (created_on/updated_on) for PostgreSQL 985 [dave@cherryville.org]
  • Fixed Base.silence/benchmark to only log if a logger has been configured 986 [skaes@web.de]
  • Added a join parameter as the third argument to Base.find_first and as the second to Base.count 426, 988 [skaes@web.de]
  • Fixed bug in Base#hash method that would treat records with the same string-based id as different [Dave Thomas]
  • Renamed DateHelper#distance_of_time_in_words_to_now to DateHelper#time_ago_in_words (old method name is still available as a deprecated alias)

*1.9.1* (27th March, 2005)

  • Fixed that Active Record objects with float attribute could not be cloned 808
  • Fixed that MissingSourceFile‘s wasn‘t properly detected in production mode 925 [Nicholas Seckar]
  • Fixed that :counter_cache option would look for a line_items_count column for a LineItem object instead of lineitems_count
  • Fixed that AR exists?() would explode on postgresql if the passed id did not match the PK type 900 [Scott Barron]
  • Fixed the MS SQL adapter to work with the new limit/offset approach and with binary data (still suffering from 7KB limit, though) 901 [delynnb]

*1.9.0* (22th March, 2005)

  • Added adapter independent limit clause as a two-element array with the first being the limit, the second being the offset 795 [Sam Stephenson]. Example:
      Developer.find_all nil, 'id ASC', 5      # return the first five developers
  Developer.find_all nil, 'id ASC', [3, 8] # return three developers, starting from #8 and forward

    This doesn‘t yet work with the DB2 or MS SQL adapters. Patches to make that happen are encouraged.

  • Added alias_method :to_param, :id to Base, such that Active Record objects to be used as URL parameters in Action Pack automatically 812 [Nicholas Seckar/Sam Stephenson]
  • Improved the performance of the OCI8 adapter for Oracle 723 [pilx/gjenkins]
  • Added type conversion before saving a record, so string-based values like "10.0" aren‘t left for the database to convert 820 [dave@cherryville.org]
  • Added with additional settings for working with transactional fixtures and pre-loaded test databases 865 [mindel]
  • Fixed acts_as_list to trigger remove_from_list on destroy after the fact, not before, so a unique position can be maintained 871 [Alisdair McDiarmid]
  • Added the possibility of specifying fixtures in multiple calls 816 [kim@tinker.com]
  • Added Base.exists?(id) that‘ll return true if an object of the class with the given id exists 854 [stian@grytoyr.net]
  • Added optionally allow for nil or empty strings with validates_numericality_of 801 [Sebastian Kanthak]
  • Fixed problem with using slashes in validates_format_of regular expressions 801 [Sebastian Kanthak]
  • Fixed that SQLite3 exceptions are caught and reported properly 823 [yerejm]
  • Added that all types of after_find/after_initialized callbacks are triggered if the explicit implementation is present, not only the explicit implementation itself
  • Fixed that symbols can be used on attribute assignment, like page.emails.create(:subject => data.subject, :body => data.body)

*1.8.0* (7th March, 2005)

  • Added ActiveRecord::Base.colorize_logging to control whether to use colors in logs or not (on by default)
  • Added support for timestamp with time zone in PostgreSQL 560 [Scott Barron]
  • Added MultiparameterAssignmentErrors and AttributeAssignmentError exceptions 777 [demetrius]. Documentation:
     * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
   +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
   objects that should be inspected to determine which attributes triggered the errors.
 * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
   You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
  • Fixed that postgresql adapter would fails when reading bytea fields with null value 771 [rodrigo k]
  • Added transactional fixtures that uses rollback to undo changes to fixtures instead of DELETE/INSERT — it‘s much faster. See documentation under Fixtures 760 [Jeremy Kemper]
  • Added destruction of dependent objects in has_one associations when a new assignment happens 742 [mindel]. Example:
      class Account < ActiveRecord::Base
    has_one :credit_card, :dependent => true
  end
  class CreditCard < ActiveRecord::Base
    belongs_to :account
  end

  account.credit_card # => returns existing credit card, lets say id = 12
  account.credit_card = CreditCard.create("number" => "123")
  account.save # => CC with id = 12 is destroyed
  • Added validates_numericality_of 716 [skanthak/c.r.mcgrath]. Docuemntation:
      Validates whether the value of the specified attribute is numeric by trying to convert it to
  a float with Kernel.Float (if <tt>integer</tt> is false) or applying it to the regular expression
  <tt>/^[\+\-]?\d+$/</tt> (if <tt>integer</tt> is set to true).

    class Person < ActiveRecord::Base
      validates_numericality_of :value, :on => :create
    end

  Configuration options:
  * <tt>message</tt> - A custom error message (default is: "is not a number")
  * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
  * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
  • Fixed that HasManyAssociation#count was using :finder_sql rather than :counter_sql if it was available 445 [Scott Barron]
  • Added better defaults for composed_of, so statements like composed_of :time_zone, :mapping => %w( time_zone time_zone ) can be written without the mapping part (it‘s now assumed)
  • Added MacroReflection#macro which will return a symbol describing the macro used (like :composed_of or :has_many) 718, 248 [james@slashetc.com]

*1.7.0* (24th February, 2005)

  • Changed the auto-timestamping feature to use ActiveRecord::Base.default_timezone instead of entertaining the parallel ActiveRecord::Base.timestamps_gmt method. The latter is now deprecated and will throw a warning on use (but still work) 710 [Jamis Buck]
  • Added a OCI8-based Oracle adapter that has been verified to work with Oracle 8 and 9 629 [Graham Jenkins]. Usage notes:
      1.  Key generation uses a sequence "rails_sequence" for all tables. (I couldn't find a simple
      and safe way of passing table-specific sequence information to the adapter.)
  2.  Oracle uses DATE or TIMESTAMP datatypes for both dates and times. Consequently I have had to
      resort to some hacks to get data converted to Date or Time in Ruby.
      If the column_name ends in _at (like created_at, updated_at) it's created as a Ruby Time. Else if the
      hours/minutes/seconds are 0, I make it a Ruby Date. Else it's a Ruby Time.
      This is nasty - but if you use Duck Typing you'll probably not care very much.
      In 9i it's tempting to map DATE to Date and TIMESTAMP to Time but I don't think that is
      valid - too many databases use DATE for both.
      Timezones and sub-second precision on timestamps are not supported.
  3.  Default values that are functions (such as "SYSDATE") are not supported. This is a
      restriction of the way active record supports default values.
  4.  Referential integrity constraints are not fully supported. Under at least
      some circumstances, active record appears to delete parent and child records out of
      sequence and out of transaction scope. (Or this may just be a problem of test setup.)

    The OCI8 driver can be retrieved from rubyforge.org/projects/ruby-oci8/

  • Added option :schema_order to the PostgreSQL adapter to support the use of multiple schemas per database 697 [YuriSchimke]
  • Optimized the SQL used to generate has_and_belongs_to_many queries by listing the join table first 693 [yerejm]
  • Fixed that when using validation macros with a custom message, if you happened to use single quotes in the message string you would get a parsing error 657 [tonka]
  • Fixed that Active Record would throw Broken Pipe errors with FCGI when the MySQL connection timed out instead of reconnecting 428 [Nicholas Seckar]
  • Added options to specify an SSL connection for MySQL. Define the following attributes in the connection config (config/database.yml in Rails) to use it: sslkey, sslcert, sslca, sslcapath, sslcipher. To use SSL with no client certs, just set :sslca = ’/dev/null’. dev.mysql.com/doc/mysql/en/secure-connections.html 604 [daniel@nightrunner.com]
  • Added automatic dropping/creating of test tables for running the unit tests on all databases 587 [adelle@bullet.net.au]
  • Fixed that find_by_* would fail when column names had numbers 670 [demetrius]
  • Fixed the SQL Server adapter on a bunch of issues 667 [DeLynn]
      1. Created a new columns method that is much cleaner.
  2. Corrected a problem with the select and select_all methods
     that didn't account for the LIMIT clause being passed into raw SQL statements.
  3. Implemented the string_to_time method in order to create proper instances of the time class.
  4. Added logic to the simplified_type method that allows the database to specify the scale of float data.
  5. Adjusted the quote_column_name to account for the fact that MS SQL is bothered by a forward slash in the data string.
  • Fixed that the dynamic finder like find_all_by_something_boolean(false) didn‘t work 649 [lmarlow@yahoo.com]
  • Added validates_each that validates each specified attribute against a block 610 [Jeremy Kemper]. Example:
      class Person < ActiveRecord::Base
    validates_each :first_name, :last_name do |record, attr|
      record.errors.add attr, 'starts with z.' if attr[0] == ?z
    end
  end
  • Added :allow_nil as an explicit option for validates_length_of, so unless that‘s set to true having the attribute as nil will also return an error if a range is specified as :within 610 [Jeremy Kemper]
  • Added that validates_* now accept blocks to perform validations 618 [Tim Bates]. Example:
      class Person < ActiveRecord::Base
    validate { |person| person.errors.add("title", "will never be valid") if SHOULD_NEVER_BE_VALID }
  end
  • Addded validation for validate all the associated objects before declaring failure with validates_associated 618 [Tim Bates]
  • Added keyword-style approach to defining the custom relational bindings 545 [Jamis Buck]. Example:
      class Project < ActiveRecord::Base
    primary_key "sysid"
    table_name "XYZ_PROJECT"
    inheritance_column { original_inheritance_column + "_id" }
  end
  • Fixed Base#clone for use with PostgreSQL 565 [hanson@surgery.wisc.edu]

*1.6.0* (January 25th, 2005)

  • Added that has_many association build and create methods can take arrays of record data like Base#create and Base#build to build/create multiple records at once.
  • Added that Base#delete and Base#destroy both can take an array of ids to delete/destroy 336
  • Added the option of supplying an array of attributes to Base#create, so that multiple records can be created at once.
  • Added the option of supplying an array of ids and attributes to Base#update, so that multiple records can be updated at once (inspired by 526/Duane Johnson). Example
      people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
  Person.update(people.keys, people.values)
  • Added ActiveRecord::Base.timestamps_gmt that can be set to true to make the automated timestamping use GMT instead of local time 520 [Scott Baron]
  • Added that update_all calls sanitize_sql on its updates argument, so stuff like MyRecord.update_all([‘time = ?’, Time.now]) works 519 [notahat]
  • Fixed that the dynamic finders didn‘t treat nil as a "IS NULL" but rather "= NULL" case 515 [Demetrius]
  • Added bind-named arrays for interpolating a group of ids or strings in conditions 528 [Jeremy Kemper]
  • Added that has_and_belongs_to_many associations with additional attributes also can be created between unsaved objects and only committed to the database when Base#save is called on the associator 524 [Eric Anderson]
  • Fixed that records fetched with piggy-back attributes or through rich has_and_belongs_to_many associations couldn‘t be saved due to the extra attributes not part of the table 522 [Eric Anderson]
  • Added mass-assignment protection for the inheritance column — regardless of a custom column is used or not
  • Fixed that association proxies would fail === tests like PremiumSubscription === @account.subscription
  • Fixed that column aliases didn‘t work as expected with the new MySql411 driver 507 [Demetrius]
  • Fixed that find_all would produce invalid sql when called sequentialy 490 [Scott Baron]

*1.5.1* (January 18th, 2005)

  • Fixed that the belongs_to and has_one proxy would fail a test like ‘if project.manager’ — this unfortunately also means that you can‘t call methods like project.manager.build unless there already is a manager on the project 492 [Tim Bates]
  • Fixed that the Ruby/MySQL adapter wouldn‘t connect if the password was empty 503 [Pelle]

*1.5.0* (January 17th, 2005)

  • Fixed that unit tests for MySQL are now run as the "rails" user instead of root 455 [Eric Hodel]
  • Added validates_associated that enables validation of objects in an unsaved association 398 [Tim Bates]. Example:
      class Book < ActiveRecord::Base
    has_many :pages
    belongs_to :library

    validates_associated :pages, :library
  end
  • Added support for associating unsaved objects 402 [Tim Bates]. Rules that govern this addition:
      == Unsaved objects and associations

  You can manipulate objects and associations before they are saved to the database, but there is some special behaviour you should be
  aware of, mostly involving the saving of associated objects.

  === One-to-one associations

  * Assigning an object to a has_one association automatically saves that object, and the object being replaced (if there is one), in
    order to update their primary keys - except if the parent object is unsaved (new_record? == true).
  * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns false and the assignment
    is cancelled.
  * If you wish to assign an object to a has_one association without saving it, use the #association.build method (documented below).
  * Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does
    not save the parent either.

  === Collections

  * Adding an object to a collection (has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object
    (the owner of the collection) is not yet stored in the database.
  * If saving any of the objects being added to a collection (via #push or similar) fails, then #push returns false.
  * You can add an object to a collection without automatically saving it by using the #collection.build method (documented below).
  * All unsaved (new_record? == true) members of the collection are automatically saved when the parent is saved.
  • Added replace to associations, so you can do project.manager.replace(new_manager) or project.milestones.replace(new_milestones) 402 [Tim Bates]
  • Added build and create methods to has_one and belongs_to associations, so you can now do project.manager.build(attributes) 402 [Tim Bates]
  • Added that if a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last. 402 [Tim Bates]
  • Fixed that Base#== wouldn‘t work for multiple references to the same unsaved object 402 [Tim Bates]
  • Fixed binary support for PostgreSQL 444 [alex@byzantine.no]
  • Added a differenciation between AssociationCollection#size and -length. Now AssociationCollection#size returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn‘t been loaded and calling collection.size if it has. If it‘s more likely than not that the collection does have a size larger than zero and you need to fetch that collection afterwards, it‘ll take one less SELECT query if you use length.
  • Added Base#attributes that returns a hash of all the attributes with their names as keys and clones of their objects as values 433 [atyp.de]
  • Fixed that foreign keys named the same as the association would cause stack overflow 437 [Eric Anderson]
  • Fixed default scope of acts_as_list from "1" to "1 = 1", so it‘ll work in PostgreSQL (among other places) 427 [Alexey]
  • Added Base#reload that reloads the attributes of an object from the database 422 [Andreas Schwarz]
  • Added SQLite3 compatibility through the sqlite3-ruby adapter by Jamis Buck 381 [Jeremy Kemper]
  • Added support for the new protocol spoken by MySQL 4.1.1+ servers for the Ruby/MySQL adapter that ships with Rails 440 [Matt Mower]
  • Added that Observers can use the observes class method instead of overwriting self.observed_class().
      Before:
    class ListSweeper < ActiveRecord::Base
      def self.observed_class() [ List, Item ]
    end

  After:
    class ListSweeper < ActiveRecord::Base
      observes List, Item
    end
  • Fixed that conditions in has_many and has_and_belongs_to_many should be interpolated just like the finder_sql is
  • Fixed Base#update_attribute to be indifferent to whether a string or symbol is used to describe the name
  • Added Base#toggle(attribute) and Base#toggle!(attribute) that makes it easier to flip a switch or flag.
      Before: topic.update_attribute(:approved, !approved?)
  After : topic.toggle!(:approved)
  • Added Base#increment!(attribute) and Base#decrement!(attribute) that also saves the records. Example:
      page.views # => 1
  page.increment!(:views) # executes an UPDATE statement
  page.views # => 2

  page.increment(:views).increment!(:views)
  page.views # => 4
  • Added Base#increment(attribute) and Base#decrement(attribute) that encapsulates the += 1 and -= 1 patterns.

*1.4.0* (January 4th, 2005)

  • Added automated optimistic locking if the field lock_version is present. Each update to the record increments the lock_version column and the locking facilities ensure that records instantiated twice will let the last one saved raise a StaleObjectError if the first was also updated. Example:
      p1 = Person.find(1)
  p2 = Person.find(1)

  p1.first_name = "Michael"
  p1.save

  p2.first_name = "should fail"
  p2.save # Raises a ActiveRecord::StaleObjectError

    You‘re then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.

    384 [Michael Koziarski]

  • Added dynamic attribute-based finders as a cleaner way of getting objects by simple queries without turning to SQL. They work by appending the name of an attribute to find_by_, so you get finders like Person.find_by_user_name, Payment.find_by_transaction_id. So instead of writing Person.find_first(["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name).

    It‘s also possible to use multiple attributes in the same find by separating them with "and", so you get finders like Person.find_by_user_name_and_password or even Payment.find_by_purchaser_and_state_and_country. So instead of writing Person.find_first(["user_name = ? AND password = ?", user_name, password]), you just do Person.find_by_user_name_and_password(user_name, password).

    While primarily a construct for easier find_firsts, it can also be used as a construct for find_all by using calls like Payment.find_all_by_amount(50) that is turned into Payment.find_all(["amount = ?", 50]). This is something not as equally useful, though, as it‘s not possible to specify the order in which the objects are returned.

  • Added block-style for callbacks 332 [Jeremy Kemper].
      Before:
    before_destroy(Proc.new{ |record| Person.destroy_all "firm_id = #{record.id}" })

  After:
    before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
  • Added :counter_cache option to acts_as_tree that works just like the one you can define on belongs_to 371 [Josh]
  • Added Base.default_timezone accessor that determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database. This is set to :local by default.
  • Added the possibility for adapters to overwrite add_limit! to implement a different limiting scheme than "LIMIT X" used by MySQL, PostgreSQL, and SQLite.
  • Added the possibility of having objects with acts_as_list created before their scope is available or…
  • Added a db2 adapter that only depends on the Ruby/DB2 bindings (raa.ruby-lang.org/project/ruby-db2/) 386 [Maik Schmidt]
  • Added the final touches to the Microsoft SQL Server adapter by Joey Gibson that makes it suitable for actual use 394 [DeLynn Barry]
  • Added that Base#find takes an optional options hash, including :conditions. Base#find_on_conditions deprecated in favor of find with :conditions 407 [Jeremy Kemper]
  • Added HasManyAssociation#count that works like Base#count 413 [intinig]
  • Fixed handling of binary content in blobs and similar fields for Ruby/MySQL and SQLite 409 [xal]
  • Fixed a bug in the Ruby/MySQL that caused binary content to be escaped badly and come back mangled 405 [Tobias Luetke]
  • Fixed that the const_missing autoload assumes the requested constant is set by require_association and calls const_get to retrieve it. If require_association did not set the constant then const_get will call const_missing, resulting in an infinite loop 380 [Jeremy Kemper]
  • Fixed broken transactions that were actually only running object-level and not db level transactions [andreas]
  • Fixed that validates_uniqueness_of used ‘id’ instead of defined primary key 406
  • Fixed that the overwritten respond_to? method didn‘t take two parameters like the original 391
  • Fixed quoting in validates_format_of that would allow some rules to pass regardless of input 390 [Dmitry V. Sabanin]

*1.3.0* (December 23, 2004)

  • Added a require_association hook on const_missing that makes it possible to use any model class without requiring it first. This makes STI look like:
      before:
    require_association 'person'
    class Employee < Person
    end

  after:
    class Employee < Person
    end

    This also reduces the usefulness of Controller.model in Action Pack to currently only being for documentation purposes.

  • Added that Base.update_all and Base.delete_all return an integer of the number of affected rows 341
  • Added scope option to validation_uniqueness 349 [Kent Sibilev]
  • Added respondence to *_before_type_cast for all attributes to return their string-state before they were type casted by the column type. This is helpful for getting "100,000" back on a integer-based validation where the value would normally be "100".
  • Added allow_nil options to validates_inclusion_of so that validation is only triggered if the attribute is not nil [what-a-day]
  • Added work-around for PostgreSQL and the problem of getting fixtures to be created from id 1 on each test case. This only works for auto-incrementing primary keys called "id" for now 359 [Scott Baron]
  • Added Base#clear_association_cache to empty all the cached associations 347 [Tobias Luetke]
  • Added more informative exceptions in establish_connection 356 [Jeremy Kemper]
  • Added Base#update_attributes that‘ll accept a hash of attributes and save the record (returning true if it passed validation, false otherwise).
      Before:
    person.attributes = @params["person"]
    person.save

  Now:
    person.update_attributes(@params["person"])
  • Added Base.destroy and Base.delete to remove records without holding a reference to them first.
  • Added that query benchmarking will only happen if its going to be logged anyway 344
  • Added higher_item and lower_item as public methods for acts_as_list 342 [Tobias Luetke]
  • Fixed that options[:counter_sql] was overwritten with interpolated sql rather than original sql 355 [Jeremy Kemper]
  • Fixed that overriding an attribute‘s accessor would be disregarded by add_on_empty and add_on_boundary_breaking because they simply used the attributes[] hash instead of checking for @base.respond_to?(attr.to_s). [Marten]
  • Fixed that Base.table_name would expect a parameter when used in has_and_belongs_to_many joins [Anna Lissa Cruz]
  • Fixed that nested transactions now work by letting the outer most transaction have the responsibilty of starting and rolling back the transaction. If any of the inner transactions swallow the exception raised, though, the transaction will not be rolled back. So always let the transaction bubble up even when you‘ve dealt with local issues. Closes 231 and 340.
  • Fixed validates_{confirmation,acceptance}_of to only happen when the virtual attributes are not nil 348 [dpiddy@gmail.com]
  • Changed the interface on AbstractAdapter to require that adapters return the number of affected rows on delete and update operations.
  • Fixed the automated timestamping feature when running under Rails’ development environment that resets the inheritable attributes on each request.

*1.2.0*

  • Added Base.validates_inclusion_of that validates whether the value of the specified attribute is available in a particular enumerable object. [what-a-day]
      class Person < ActiveRecord::Base
    validates_inclusion_of :gender, :in=>%w( m f ), :message=>"woah! what are you then!??!!"
    validates_inclusion_of :age, :in=>0..99
  end
  • Added acts_as_list that can decorates an existing class with methods like move_higher/lower, move_to_top/bottom. [Tobias Luetke] Example:
      class TodoItem < ActiveRecord::Base
    acts_as_list :scope => :todo_list_id
    belongs_to :todo_list
  end
  • Added acts_as_tree that can decorates an existing class with a many to many relationship with itself. Perfect for categories in categories and the likes. [Tobias Luetke]
  • Added that Active Records will automatically record creation and/or update timestamps of database objects if fields of the names created_at/created_on or updated_at/updated_on are present. [Tobias Luetke]
  • Added Base.default_error_messages as a hash of all the error messages used in the validates_*_of so they can be changed in one place [Tobias Luetke]
  • Added automatic transaction block around AssociationCollection.<<, AssociationCollection.delete, and AssociationCollection.destroy_all
  • Fixed that Base#find will return an array if given an array — regardless of the number of elements 270 [Marten]
  • Fixed that has_and_belongs_to_many would generate bad sql when naming conventions differed from using vanilla "id" everywhere [RedTerror]
  • Added a better exception for when a type column is used in a table without the intention of triggering single-table inheritance. Example:
      ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'bad_class!'.
  This error is raised because the column 'type' is reserved for storing the class in case of inheritance.
  Please rename this column if you didn't intend it to be used for storing the inheritance class or
  overwrite Company.inheritance_column to use another column for that information.
  • Added that single-table inheritance will only kick in if the inheritance_column (by default "type") is present. Otherwise, inheritance won‘t have any magic side effects.
  • Added the possibility of marking fields as being in error without adding a message (using nil) to it that‘ll get displayed wth full_messages 208 [mjobin]
  • Fixed Base.errors to be indifferent as to whether strings or symbols are used. Examples:
      Before:
    errors.add(:name, "must be shorter") if name.size > 10
    errors.on(:name)  # => "must be shorter"
    errors.on("name") # => nil

  After:
    errors.add(:name, "must be shorter") if name.size > 10
    errors.on(:name)  # => "must be shorter"
    errors.on("name") # => "must be shorter"
  • Added Base.validates_format_of that Validates whether the value of the specified attribute is of the correct form by matching it against the regular expression provided. [Marcel]
      class Person < ActiveRecord::Base
    validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/, :on => :create
  end
  • Added Base.validates_length_of that delegates to add_on_boundary_breaking 312 [Tobias Luetke]. Example:
      Validates that the specified attribute matches the length restrictions supplied in either:

    - configuration[:minimum]
    - configuration[:maximum]
    - configuration[:is]
    - configuration[:within] (aka. configuration[:in])

  Only one option can be used at a time.

    class Person < ActiveRecord::Base
      validates_length_of :first_name, :maximum=>30
      validates_length_of :last_name, :maximum=>30, :message=>"less than %d if you don't mind"
      validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
      validates_length_of :fav_bra_size, :minimum=>1, :too_short=>"please enter at least %d character"
      validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me."
    end
  • Added Base.validate_presence as an alternative to implementing validate and doing errors.add_on_empty yourself.
  • Added Base.validates_uniqueness_of that alidates whether the value of the specified attributes are unique across the system. Useful for making sure that only one user can be named "davidhh".
      class Person < ActiveRecord::Base
    validates_uniqueness_of :user_name
  end

    When the record is created, a check is performed to make sure that no record exist in the database with the given value for the specified attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself.

  • Added Base.validates_confirmation_of that encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
       Model:
     class Person < ActiveRecord::Base
       validates_confirmation_of :password
     end

   View:
     <%= password_field "person", "password" %>
     <%= password_field "person", "password_confirmation" %>

 The person has to already have a password attribute (a column in the people table), but the password_confirmation is virtual.
 It exists only as an in-memory variable for validating the password. This check is performed both on create and update.
  • Added Base.validates_acceptance_of that encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
     class Person < ActiveRecord::Base
   validates_acceptance_of :terms_of_service
 end

    The terms_of_service attribute is entirely virtual. No database column is needed. This check is performed both on create and update.

    NOTE: The agreement is considered valid if it‘s set to the string "1". This makes it easy to relate it to an HTML checkbox.

  • Added validation macros to make the stackable just like the lifecycle callbacks. Examples:
      class Person < ActiveRecord::Base
    validate { |record| record.errors.add("name", "too short") unless name.size > 10 }
    validate { |record| record.errors.add("name", "too long")  unless name.size < 20 }
    validate_on_create :validate_password

    private
      def validate_password
        errors.add("password", "too short") unless password.size > 6
      end
  end
  • Added the option for sanitizing find_by_sql and the offset parts in regular finds [Sam Stephenson]. Examples:
      Project.find_all ["category = ?", category_name], "created ASC", ["? OFFSET ?", 15, 20]
  Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
  • Fixed value quoting in all generated SQL statements, so that integers are not surrounded in quotes and that all sanitation are happening through the database‘s own quoting routine. This should hopefully make it lots easier for new adapters that doesn‘t accept ‘1’ for integer columns.
  • Fixed has_and_belongs_to_many guessing of foreign key so that keys are generated correctly for models like SomeVerySpecialClient [Florian Weber]
  • Added counter_sql option for has_many associations [Jeremy Kemper]. Documentation:
      <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If +:finder_sql+ is
  specified but +:counter_sql+, +:counter_sql+ will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM.
  • Fixed that methods wrapped in callbacks still return their original result 260 [Jeremy Kemper]
  • Fixed the Inflector to handle the movie/movies pair correctly 261 [Scott Baron]
  • Added named bind-style variable interpolation 281 [Michael Koziarski]. Example:
      Person.find(["id = :id and first_name = :first_name", { :id => 5, :first_name = "bob' or 1=1" }])
  • Added bind-style variable interpolation for the condition arrays that uses the adapter‘s quote method [Michael Koziarski]

    Before:

      find_first([ "user_name = '%s' AND password = '%s'", user_name, password ])]
  find_first([ "firm_id = %s", firm_id ])] # unsafe!

    After:

      find_first([ "user_name = ? AND password = ?", user_name, password ])]
  find_first([ "firm_id = ?", firm_id ])]
  • Added CSV format for fixtures 272 [what-a-day]. (See the new and expanded documentation on fixtures for more information)
  • Fixed fixtures using primary key fields called something else than "id" [dave]
  • Added proper handling of time fields that are turned into Time objects with the dummy date of 2000/1/1 [HariSeldon]
  • Added reverse order of deleting fixtures, so referential keys can be maintained 247 [Tim Bates]
  • Added relative path search for sqlite dbfiles in database.yml (if RAILS_ROOT is defined) 233 [Jeremy Kemper]
  • Added option to establish_connection where you‘ll be able to leave out the parameter to have it use the RAILS_ENV environment variable
  • Fixed problems with primary keys and postgresql sequences (230) [Tim Bates]
  • Added reloading for associations under cached environments like FastCGI and mod_ruby. This makes it possible to use those environments for development. This is turned on by default, but can be turned off with ActiveRecord::Base.reload_dependencies = false in production environments.

    NOTE: This will only have an effect if you let the associations manage the requiring of model classes. All libraries loaded through require will be "forever" cached. You can, however, use ActiveRecord::Base.load_or_require("library") to get this behavior outside of the auto-loading associations.

  • Added ERB capabilities to the fixture files for dynamic fixture generation. You don‘t need to do anything, just include ERB blocks like:
      david:
    id: 1
    name: David

  jamis:
    id: 2
    name: Jamis

  <% for digit in 3..10 %>
  dev_<%= digit %>:
    id: <%= digit %>
    name: fixture_<%= digit %>
  <% end %>
  • Changed the yaml fixture searcher to look in the root of the fixtures directory, so when you before could have something like:
      fixtures/developers/fixtures.yaml
  fixtures/accounts/fixtures.yaml

    …you now need to do:

      fixtures/developers.yaml
  fixtures/accounts.yaml
  • Changed the fixture format from:
      name: david
  data:
   id: 1
   name: David Heinemeier Hansson
   birthday: 1979-10-15
   profession: Systems development
  ---
  name: steve
  data:
   id: 2
   name: Steve Ross Kellock
   birthday: 1974-09-27
   profession: guy with keyboard

    …to:

      david:
   id: 1
   name: David Heinemeier Hansson
   birthday: 1979-10-15
   profession: Systems development

  steve:
   id: 2
   name: Steve Ross Kellock
   birthday: 1974-09-27
   profession: guy with keyboard

    The change is NOT backwards compatible. Fixtures written in the old YAML style needs to be rewritten!

  • All associations will now attempt to require the classes that they associate to. Relieving the need for most explicit ‘require’ statements.

*1.1.0* (34)

  • Added automatic fixture setup and instance variable availability. Fixtures can also be automatically instantiated in instance variables relating to their names using the following style:
      class FixturesTest < Test::Unit::TestCase
    fixtures :developers # you can add more with comma separation

    def test_developers
      assert_equal 3, @developers.size # the container for all the fixtures is automatically set
      assert_kind_of Developer, @david # works like @developers["david"].find
      assert_equal "David Heinemeier Hansson", @david.name
    end
  end
  • Added HasAndBelongsToManyAssociation#push_with_attributes(object, join_attributes) that can create associations in the join table with additional attributes. This is really useful when you have information that‘s only relevant to the join itself, such as a "added_on" column for an association between post and category. The added attributes will automatically be injected into objects retrieved through the association similar to the piggy-back approach:
      post.categories.push_with_attributes(category, :added_on => Date.today)
  post.categories.first.added_on # => Date.today

    NOTE: The categories table doesn‘t have a added_on column, it‘s the categories_post join table that does!

  • Fixed that :exclusively_dependent and :dependent can‘t be activated at the same time on has_many associations [Jeremy Kemper]
  • Fixed that database passwords couldn‘t be all numeric [Jeremy Kemper]
  • Fixed that calling id would create the instance variable for new_records preventing them from being saved correctly [Jeremy Kemper]
  • Added sanitization feature to HasManyAssociation#find_all so it works just like Base.find_all [Sam Stephenson/bitsweat]
  • Added that you can pass overlapping ids to find without getting duplicated records back [Jeremy Kemper]
  • Added that Base.benchmark returns the result of the block [Jeremy Kemper]
  • Fixed problem with unit tests on Windows with SQLite [paterno]
  • Fixed that quotes would break regular non-yaml fixtures [Dmitry Sabanin/daft]
  • Fixed fixtures on windows with line endings cause problems under unix / mac [Tobias Luetke]
  • Added HasAndBelongsToManyAssociation#find(id) that‘ll search inside the collection and find the object or record with that id
  • Added :conditions option to has_and_belongs_to_many that works just like the one on all the other associations
  • Added AssociationCollection#clear to remove all associations from has_many and has_and_belongs_to_many associations without destroying the records [geech]
  • Added type-checking and remove in 1-instead-of-N sql statements to AssociationCollection#delete [geech]
  • Added a return of self to AssociationCollection#<< so appending can be chained, like project << Milestone.create << Milestone.create [geech]
  • Added Base#hash and Base#eql? which means that all of the equality using features of array and other containers now works:
      [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
  • Added :uniq as an option to has_and_belongs_to_many which will automatically ensure that AssociateCollection#uniq is called before pulling records out of the association. This is especially useful for three-way (and above) has_and_belongs_to_many associations.
  • Added AssociateCollection#uniq which is especially useful for has_and_belongs_to_many associations that can include duplicates, which is common on associations that also use metadata. Usage: post.categories.uniq
  • Fixed respond_to? to use a subclass specific hash instead of an Active Record-wide one
  • Fixed has_and_belongs_to_many to treat associations between classes in modules properly [Florian Weber]
  • Added a NoMethod exception to be raised when query and writer methods are called for attributes that doesn‘t exist [geech]
  • Added a more robust version of Fixtures that throws meaningful errors when on formatting issues [geech]
  • Added Base#transaction as a compliment to Base.transaction for prettier use in instance methods [geech]
  • Improved the speed of respond_to? by placing the dynamic methods lookup table in a hash [geech]
  • Added that any additional fields added to the join table in a has_and_belongs_to_many association will be placed as attributes when pulling records out through has_and_belongs_to_many associations. This is helpful when have information about the association itself that you want available on retrival.
  • Added better loading exception catching and RubyGems retries to the database adapters [alexeyv]
  • Fixed bug with per-model transactions [daniel]
  • Fixed Base#transaction so that it returns the result of the last expression in the transaction block [alexeyv]
  • Added Fixture#find to find the record corresponding to the fixture id. The record class name is guessed by using Inflector#classify (also new) on the fixture directory name.
      Before: Document.find(@documents["first"]["id"])
  After : @documents["first"].find
  • Fixed that the table name part of column names ("TABLE.COLUMN") wasn‘t removed properly [Andreas Schwarz]
  • Fixed a bug with Base#size when a finder_sql was used that didn‘t capitalize SELECT and FROM [geech]
  • Fixed quoting problems on SQLite by adding quote_string to the AbstractAdapter that can be overwritten by the concrete adapters for a call to the dbm. [Andreas Schwarz]
  • Removed RubyGems backup strategy for requiring SQLite-adapter — if people want to use gems, they‘re already doing it with AR.

*1.0.0 (35)*

  • Added OO-style associations methods [Florian Weber]. Examples:
      Project#milestones_count       => Project#milestones.size
  Project#build_to_milestones    => Project#milestones.build
  Project#create_for_milestones  => Project#milestones.create
  Project#find_in_milestones     => Project#milestones.find
  Project#find_all_in_milestones => Project#milestones.find_all
  • Added serialize as a new class method to control when text attributes should be YAMLized or not. This means that automated serialization of hashes, arrays, and so on WILL NO LONGER HAPPEN (10). You need to do something like this:
      class User < ActiveRecord::Base
    serialize :settings
  end

    This will assume that settings is a text column and will now YAMLize any object put in that attribute. You can also specify an optional :class_name option that‘ll raise an exception if a serialized object is retrieved as a descendent of a class not in the hierarchy. Example:

      class User < ActiveRecord::Base
    serialize :settings, :class_name => "Hash"
  end

  user = User.create("settings" => %w( one two three ))
  User.find(user.id).settings # => raises SerializationTypeMismatch
  • Added the option to connect to a different database for one model at a time. Just call establish_connection on the class you want to have connected to another database than Base. This will automatically also connect decendents of that class to the different database [Renald Buter].
  • Added transactional protection for Base#save. Validations can now check for values knowing that it happens in a transaction and callbacks can raise exceptions knowing that the save will be rolled back. [Suggested by Alexey Verkhovsky]
  • Added column name quoting so reserved words, such as "references", can be used as column names [Ryan Platte]
  • Added the possibility to chain the return of what happened inside a logged block [geech]:
      This now works:
    log { ... }.map { ... }

  Instead of doing:
    result = []
    log { result = ... }
    result.map { ... }
  • Added "socket" option for the MySQL adapter, so you can change it to something else than "/tmp/mysql.sock" [Anna Lissa Cruz]
  • Added respond_to? answers for all the attribute methods. So if Person has a name attribute retrieved from the table schema, person.respond_to? "name" will return true.
  • Added Base.benchmark which can be used to aggregate logging and benchmark, so you can measure and represent multiple statements in a single block. Usage (hides all the SQL calls for the individual actions and calculates total runtime for them all):
      Project.benchmark("Creating project") do
    project = Project.create("name" => "stuff")
    project.create_manager("name" => "David")
    project.milestones << Milestone.find_all
  end
  • Added logging of invalid SQL statements [Suggested by Daniel Von Fange]
  • Added alias Errors#[] for Errors#on, so you can now say person.errors["name"] to retrieve the errors for name [Andreas Schwarz]
  • Added RubyGems require attempt if sqlite-ruby is not available through regular methods.
  • Added compatibility with 2.x series of sqlite-ruby drivers. [Jamis Buck]
  • Added type safety for association assignments, so a ActiveRecord::AssociationTypeMismatch will be raised if you attempt to assign an object that‘s not of the associated class. This cures the problem with nil giving id = 4 and fixnums giving id = 1 on mistaken association assignments. [Reported by Andreas Schwarz]
  • Added the option to keep many fixtures in one single YAML document [what-a-day]
  • Added the class method "inheritance_column" that can be overwritten to return the name of an alternative column than "type" for storing the type for inheritance hierarchies. [Dave Steinberg]
  • Added [] and []= as an alternative way to access attributes when the regular methods have been overwritten [Dave Steinberg]
  • Added the option to observer more than one class at the time by specifying observed_class as an array
  • Added auto-id propagation support for tables with arbitrary primary keys that have autogenerated sequences associated with them on PostgreSQL. [Dave Steinberg]
  • Changed that integer and floats set to "" through attributes= remain as NULL. This was especially a problem for scaffolding and postgresql. (49)
  • Changed the MySQL Adapter to rely on MySQL for its defaults for socket, host, and port [Andreas Schwarz]
  • Changed ActionControllerError to decent from StandardError instead of Exception. It can now be caught by a generic rescue.
  • Changed class inheritable attributes to not use eval [Caio Chassot]
  • Changed Errors#add to now use "invalid" as the default message instead of true, which means full_messages work with those [Marcel Molina Jr]
  • Fixed spelling on Base#add_on_boundry_breaking to Base#add_on_boundary_breaking (old naming still works) [Marcel Molina Jr.]
  • Fixed that entries in the has_and_belongs_to_many join table didn‘t get removed when an associated object was destroyed.
  • Fixed unnecessary calls to SET AUTOCOMMIT=0/1 for MySQL adapter [Andreas Schwarz]
  • Fixed PostgreSQL defaults are now handled gracefully [Dave Steinberg]
  • Fixed increment/decrement_counter are now atomic updates [Andreas Schwarz]
  • Fixed the problems the Inflector had turning Attachment into attuchments and Cases into Casis [radsaq/Florian Gross]
  • Fixed that cloned records would point attribute references on the parent object [Andreas Schwarz]
  • Fixed SQL for type call on inheritance hierarchies [Caio Chassot]
  • Fixed bug with typed inheritance [Florian Weber]
  • Fixed a bug where has_many collection_count wouldn‘t use the conditions specified for that association

*0.9.5*

  • Expanded the table_name guessing rules immensely [Florian Green]. Documentation:
      Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
  directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
  to guess the table name from even when called on Reply. The guessing rules are as follows:
  * Class name ends in "x", "ch" or "ss": "es" is appended, so a Search class becomes a searches table.
  * Class name ends in "y" preceded by a consonant or "qu": The "y" is replaced with "ies",
    so a Category class becomes a categories table.
  * Class name ends in "fe": The "fe" is replaced with "ves", so a Wife class becomes a wives table.
  * Class name ends in "lf" or "rf": The "f" is replaced with "ves", so a Half class becomes a halves table.
  * Class name ends in "person": The "person" is replaced with "people", so a Salesperson class becomes a salespeople table.
  * Class name ends in "man": The "man" is replaced with "men", so a Spokesman class becomes a spokesmen table.
  * Class name ends in "sis": The "i" is replaced with an "e", so a Basis class becomes a bases table.
  * Class name ends in "tum" or "ium": The "um" is replaced with an "a", so a Datum class becomes a data table.
  * Class name ends in "child": The "child" is replaced with "children", so a NodeChild class becomes a node_children table.
  * Class name ends in an "s": No additional characters are added or removed.
  * Class name doesn't end in "s": An "s" is appended, so a Comment class becomes a comments table.
  * Class name with word compositions: Compositions are underscored, so CreditCard class becomes a credit_cards table.
  Additionally, the class-level table_name_prefix is prepended to the table_name and the table_name_suffix is appended.
  So if you have "myapp_" as a prefix, the table name guess for an Account class becomes "myapp_accounts".

  You can also overwrite this class method to allow for unguessable links, such as a Mouse class with a link to a
  "mice" table. Example:

    class Mouse < ActiveRecord::Base
       def self.table_name() "mice" end
    end

    This conversion is now done through an external class called Inflector residing in lib/active_record/support/inflector.rb.

  • Added find_all_in_collection to has_many defined collections. Works like this:
      class Firm < ActiveRecord::Base
    has_many :clients
  end

  firm.id # => 1
  firm.find_all_in_clients "revenue > 1000" # SELECT * FROM clients WHERE firm_id = 1 AND revenue > 1000

    [Requested by Dave Thomas]

  • Fixed finders for inheritance hierarchies deeper than one level [Florian Weber]
  • Added add_on_boundry_breaking to errors to accompany add_on_empty as a default validation method. It‘s used like this:
      class Person < ActiveRecord::Base
    protected
      def validation
        errors.add_on_boundry_breaking "password", 3..20
      end
  end

    This will add an error to the tune of "is too short (minimum is 3 characters)" or "is too long (minimum is 20 characters)" if the password is outside the boundry. The messages can be changed by passing a third and forth parameter as message strings.

  • Implemented a clone method that works properly with AR. It returns a clone of the record that hasn‘t been assigned an id yet and is treated as a new record.
  • Allow for domain sockets in PostgreSQL by not assuming localhost when no host is specified [Scott Barron]
  • Fixed that bignums are saved properly instead of attempted to be YAMLized [Andreas Schwartz]
  • Fixed a bug in the GEM where the rdoc options weren‘t being passed according to spec [Chad Fowler]
  • Fixed a bug with the exclusively_dependent option for has_many

*0.9.4*

  • Correctly guesses the primary key when the class is inside a module [Dave Steinberg].
  • Added [] and []= as alternatives to read_attribute and write_attribute [Dave Steinberg]
  • has_and_belongs_to_many now accepts an :order key to determine in which order the collection is returned [radsaq].
  • The ids passed to find and find_on_conditions are now automatically sanitized.
  • Added escaping of plings in YAML content.
  • Multi-parameter assigns where all the parameters are empty will now be set to nil instead of a new instance of their class.
  • Proper type within an inheritance hierarchy is now ensured already at object initialization (instead of first at create)

*0.9.3*

  • Fixed bug with using a different primary key name together with has_and_belongs_to_many [Investigation by Scott]
  • Added :exclusively_dependent option to the has_many association macro. The doc reads:
      If set to true all the associated object are deleted in one SQL statement without having their
  before_destroy callback run. This should only be used on associations that depend solely on
  this class and don't need to do any clean-up in before_destroy. The upside is that it's much
  faster, especially if there's a counter_cache involved.
  • Added :port key to connection options, so the PostgreSQL and MySQL adapters can connect to a database server running on another port than the default.
  • Converted the new natural singleton methods that prevented AR objects from being saved by PStore (and hence be placed in a Rails session) to a module. [Florian Weber]
  • Fixed the use of floats (was broken since 0.9.0+)
  • Fixed PostgreSQL adapter so default values are displayed properly when used in conjunction with Action Pack scaffolding.
  • Fixed booleans support for PostgreSQL (use real true/false on boolean fields instead of 0/1 on tinyints) [radsaq]

*0.9.2*

  • Added static method for instantly updating a record
  • Treat decimal and numeric as Ruby floats [Andreas Schwartz]
  • Treat chars as Ruby strings (fixes problem for Action Pack form helpers too)
  • Removed debugging output accidently left in (which would screw web applications)

*0.9.1*

  • Added MIT license
  • Added natural object-style assignment for has_and_belongs_to_many associations. Consider the following model:
      class Event < ActiveRecord::Base
    has_one_and_belongs_to_many :sponsors
  end

  class Sponsor < ActiveRecord::Base
    has_one_and_belongs_to_many :sponsors
  end

    Earlier, you‘d have to use synthetic methods for creating associations between two objects of the above class:

      roskilde_festival.add_to_sponsors(carlsberg)
  roskilde_festival.remove_from_sponsors(carlsberg)

  nike.add_to_events(world_cup)
  nike.remove_from_events(world_cup)

    Now you can use regular array-styled methods:

      roskilde_festival.sponsors << carlsberg
  roskilde_festival.sponsors.delete(carlsberg)

  nike.events << world_cup
  nike.events.delete(world_cup)
  • Added delete method for has_many associations. Using this will nullify an association between the has_many and the belonging object by setting the foreign key to null. Consider this model:
      class Post < ActiveRecord::Base
    has_many :comments
  end

  class Comment < ActiveRecord::Base
    belongs_to :post
  end

    You could do something like:

      funny_comment.has_post? # => true
  announcement.comments.delete(funny_comment)
  funny_comment.has_post? # => false

*0.9.0*

  • Active Record is now thread safe! (So you can use it with Cerise and WEBrick applications) [Implementation idea by Michael Neumann, debugging assistance by Jamis Buck]
  • Improved performance by roughly 400% on a basic test case of pulling 100 records and querying one attribute. This brings the tax for using Active Record instead of "riding on the metal" (using MySQL-ruby C-driver directly) down to ~50%. Done by doing lazy type conversions and caching column information on the class-level.
  • Added callback objects and procs as options for implementing the target for callback macros.
  • Added "counter_cache" option to belongs_to that automates the usage of increment_counter and decrement_counter. Consider:
      class Post < ActiveRecord::Base
    has_many :comments
  end

  class Comment < ActiveRecord::Base
    belongs_to :post
  end

    Iterating over 100 posts like this:

      <% for post in @posts %>
    <%= post.title %> has <%= post.comments_count %> comments
  <% end %>

    Will generate 100 SQL count queries — one for each call to post.comments_count. If you instead add a "comments_count" int column to the posts table and rewrite the comments association macro with:

      class Comment < ActiveRecord::Base
    belongs_to :post, :counter_cache => true
  end

    Those 100 SQL count queries will be reduced to zero. Beware that counter caching is only appropriate for objects that begin life with the object it‘s specified to belong with and is destroyed like that as well. Typically objects where you would also specify :dependent => true. If your objects switch from one belonging to another (like a post that can be move from one category to another), you‘ll have to manage the counter yourself.

  • Added natural object-style assignment for has_one and belongs_to associations. Consider the following model:
      class Project < ActiveRecord::Base
    has_one :manager
  end

  class Manager < ActiveRecord::Base
    belongs_to :project
  end

    Earlier, assignments would work like following regardless of which way the assignment told the best story:

      active_record.manager_id = david.id

    Now you can do it either from the belonging side:

      david.project = active_record

    …or from the having side:

      active_record.manager = david

    If the assignment happens from the having side, the assigned object is automatically saved. So in the example above, the project_id attribute on david would be set to the id of active_record, then david would be saved.

  • Added natural object-style assignment for has_many associations [Florian Weber]. Consider the following model:
      class Project < ActiveRecord::Base
    has_many :milestones
  end

  class Milestone < ActiveRecord::Base
    belongs_to :project
  end

    Earlier, assignments would work like following regardless of which way the assignment told the best story:

      deadline.project_id = active_record.id

    Now you can do it either from the belonging side:

      deadline.project = active_record

    …or from the having side:

      active_record.milestones << deadline

    The milestone is automatically saved with the new foreign key.

  • API CHANGE: Attributes for text (or blob or similar) columns will now have unknown classes stored using YAML instead of using to_s. (Known classes that won‘t be yamelized are: String, NilClass, TrueClass, FalseClass, Fixnum, Date, and Time). Likewise, data pulled out of text-based attributes will be attempted converged using Yaml if they have the "— " header. This was primarily done to be enable the storage of hashes and arrays without wrapping them in aggregations, so now you can do:
      user = User.find(1)
  user.preferences = { "background" => "black", "display" => large }
  user.save

  User.find(1).preferences # => { "background" => "black", "display" => large }

    Please note that this method should only be used when you don‘t care about representing the object in proper columns in the database. A money object consisting of an amount and a currency is still a much better fit for a value object done through aggregations than this new option.

  • POSSIBLE CODE BREAKAGE: As a consequence of the lazy type conversions, it‘s a bad idea to reference the @attributes hash directly (it always was, but now it‘s paramount that you don‘t). If you do, you won‘t get the type conversion. So to implement new accessors for existing attributes, use read_attribute(attr_name) and write_attribute(attr_name, value) instead. Like this:
      class Song < ActiveRecord::Base
    # Uses an integer of seconds to hold the length of the song

    def length=(minutes)
      write_attribute("length", minutes * 60)
    end

    def length
      read_attribute("length") / 60
    end
  end

    The clever kid will notice that this opens a door to sidestep the automated type conversion by using @attributes directly. This is not recommended as read/write_attribute may be granted additional responsibilities in the future, but if you think you know what you‘re doing and aren‘t afraid of future consequences, this is an option.

  • Applied a few minor bug fixes reported by Daniel Von Fange.

*0.8.4*

Reflection

  • Added ActiveRecord::Reflection with a bunch of methods and classes for reflecting in aggregations and associations.
  • Added Base.columns and Base.content_columns which returns arrays of column description (type, default, etc) objects.
  • Added Base#attribute_names which returns an array of names for the attributes available on the object.
  • Added Base#column_for_attribute(name) which returns the column description object for the named attribute.

Misc

  • Added multi-parameter assignment:
      # Instantiate objects for all attribute classes that needs more than one constructor parameter. This is done
  # by calling new on the column type or aggregation type (through composed_of) object with these parameters.
  # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
  # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
  # parenteses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float,
  # s for String, and a for Array.

    This is incredibly useful for assigning dates from HTML drop-downs of month, year, and day.

  • Fixed bug with custom primary key column name and Base.find on multiple parameters.
  • Fixed bug with dependent option on has_one associations if there was no associated object.

*0.8.3*

Transactions

  • Added transactional protection for destroy (important for the new :dependent option) [Suggested by Carl Youngblood]
  • Fixed so transactions are ignored on MyISAM tables for MySQL (use InnoDB to get transactions)
  • Changed transactions so only exceptions will cause a rollback, not returned false.

Mapping

  • Added support for non-integer primary keys [Aredridel/earlier work by Michael Neumann]
      User.find "jdoe"
  Product.find "PDKEY-INT-12"
  • Added option to specify naming method for primary key column. ActiveRecord::Base.primary_key_prefix_type can either be set to nil, :table_name, or :table_name_with_underscore. :table_name will assume that Product class has a primary key of "productid" and :table_name_with_underscore will assume "product_id". The default nil will just give "id".
  • Added an overwriteable primary_key method that‘ll instruct AR to the name of the id column [Aredridele/earlier work by Guan Yang]
      class Project < ActiveRecord::Base
    def self.primary_key() "project_id" end
  end
  • Fixed that Active Records can safely associate inside and out of modules.
      class MyApplication::Account < ActiveRecord::Base
    has_many :clients # will look for MyApplication::Client
    has_many :interests, :class_name => "Business::Interest" # will look for Business::Interest
  end
  • Fixed that Active Records can safely live inside modules [Aredridel]
      class MyApplication::Account < ActiveRecord::Base
  end

Misc

  • Added freeze call to value object assignments to ensure they remain immutable [Spotted by Gavin Sinclair]
  • Changed interface for specifying observed class in observers. Was OBSERVED_CLASS constant, now is observed_class() class method. This is more consistant with things like self.table_name(). Works like this:
      class AuditObserver < ActiveRecord::Observer
    def self.observed_class() Account end
    def after_update(account)
      AuditTrail.new(account, "UPDATED")
    end
  end

    [Suggested by Gavin Sinclair]

  • Create new Active Record objects by setting the attributes through a block. Like this:
      person = Person.new do |p|
    p.name = 'Freddy'
    p.age  = 19
  end

    [Suggested by Gavin Sinclair]

*0.8.2*

  • Added inheritable callback queues that can ensure that certain callback methods or inline fragments are run throughout the entire inheritance hierarchy. Regardless of whether a descendent overwrites the callback method:
      class Topic < ActiveRecord::Base
    before_destroy :destroy_author, 'puts "I'm an inline fragment"'
  end

    Learn more in classes/ActiveRecord/Callbacks.html

  • Added :dependent option to has_many and has_one, which will automatically destroy associated objects when the holder is destroyed:
      class Album < ActiveRecord::Base
    has_many :tracks, :dependent => true
  end

    All the associated tracks are destroyed when the album is.

  • Added Base.create as a factory that‘ll create, save, and return a new object in one step.
  • Automatically convert strings in config hashes to symbols for the _connection methods. This allows you to pass the argument hashes directly from yaml. (Luke)
  • Fixed the install.rb to include simple.rb [Spotted by Kevin Bullock]
  • Modified block syntax to better follow our code standards outlined in www.rubyonrails.org/CodingStandards

*0.8.1*

  • Added object-level transactions [Thanks to Austin Ziegler for Transaction::Simple]
  • Changed adapter-specific connection methods to use centralized ActiveRecord::Base.establish_connection, which is parametized through a config hash with symbol keys instead of a regular parameter list. This will allow for database connections to be opened in a more generic fashion. (Luke)

    NOTE: This requires all *_connections to be updated! Read more in: ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000081

  • Fixed SQLite adapter so objects fetched from has_and_belongs_to_many have proper attributes (t.name is now name). [Spotted by Garrett Rooney]
  • Fixed SQLite adapter so dates are returned as Date objects, not Time objects [Spotted by Gavin Sinclair]
  • Fixed requirement of date class, so date conversions are succesful regardless of whether you manually require date or not.

*0.8.0*

  • Added transactions
  • Changed Base.find to also accept either a list (1, 5, 6) or an array of ids ([5, 7]) as parameter and then return an array of objects instead of just an object
  • Fixed method has_collection? for has_and_belongs_to_many macro to behave as a collection, not an association
  • Fixed SQLite adapter so empty or nil values in columns of datetime, date, or time type aren‘t treated as current time [Spotted by Gavin Sinclair]

*0.7.6*

  • Fixed the install.rb to create the lib/active_record/support directory [Spotted by Gavin Sinclair]
  • Fixed that has_association? would always return true [Spotted by Daniel Von Fange]


File: README

File
README
Path: | activeresource/README
Modified: | Sun Mar 02 11:09:08 -0700 2008

Active Resource

Active Resource (ARes) connects business objects and Representational State Transfer (REST) web services. It implements object-relational mapping for REST webservices to provide transparent proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing in ActionController::Resources).

Philosophy

Active Resource attempts to provide a coherent wrapper object-relational mapping for REST web services. It follows the same philosophy as Active Record, in that one of its prime aims is to reduce the amount of code needed to map to these resources. This is made possible by relying on a number of code- and protocol-based conventions that make it easy for Active Resource to infer complex relations and structures. These conventions are outlined in detail in the documentation for ActiveResource::Base.

Overview

Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database tables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result received and serialized into a usable Ruby object.

Configuration and Usage

Putting ActiveResource to use is very similar to ActiveRecord. It‘s as simple as creating a model class that inherits from ActiveResource::Base and providing a site class variable to it:

   class Person < ActiveResource::Base
     self.site = "http://api.people.com:3000/"
   end

Now the Person class is REST enabled and can invoke REST services very similarly to how ActiveRecord invokes lifecycle methods that operate against a persistent store.

   # Find a person with id = 1
   ryan = Person.find(1)
   Person.exists?(1)  #=> true

As you can see, the methods are quite similar to Active Record‘s methods for dealing with database records. But rather than dealing with

Protocol

Active Resource is built on a standard XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing built into ActionController but will also work with any other REST service that properly implements the protocol. REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:

  • GET requests are used for finding and retrieving resources.
  • POST requests are used to create new resources.
  • PUT requests are used to update existing resources.
  • DELETE requests are used to delete resources.

For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation; for more general information on REST web services, see the article here.

Find

GET Http requests expect the XML form of whatever resource/resources is/are being requested. So, for a request for a single element - the XML of that item is expected in response:

   # Expects a response of
   #
   # <person><id type="integer">1</id><attribute1>value1</attribute1><attribute2>..</attribute2></person>
   #
   # for GET http://api.people.com:3000/people/1.xml
   #
   ryan = Person.find(1)

The XML document that is received is used to build a new object of type Person, with each XML element becoming an attribute on the object.

   ryan.is_a? Person  #=> true
   ryan.attribute1  #=> 'value1'

Any complex element (one that contains other elements) becomes its own object:

   # With this response:
   #
   # <person><id>1</id><attribute1>value1</attribute1><complex><attribute2>value2</attribute2></complex></person>
   #
   # for GET http://api.people.com:3000/people/1.xml
   #
   ryan = Person.find(1)
   ryan.complex  #=> <Person::Complex::xxxxx>
   ryan.complex.attribute2  #=> 'value2'

Collections can also be requested in a similar fashion

   # Expects a response of
   #
   # <people type="array">
   #  <person><id type="integer">1</id><first>Ryan</first></person>
   #  <person><id type="integer">2</id><first>Jim</first></person>
   # </people>
   #
   # for GET http://api.people.com:3000/people.xml
   #
   people = Person.find(:all)
   people.first  #=> <Person::xxx 'first' => 'Ryan' ...>
   people.last  #=> <Person::xxx 'first' => 'Jim' ...>

Create

Creating a new resource submits the xml form of the resource as the body of the request and expects a ‘Location’ header in the response with the RESTful URL location of the newly created resource. The id of the newly created resource is parsed out of the Location response header and automatically set as the id of the ARes object.

  # <person><first>Ryan</first></person>
  #
  # is submitted as the body on
  #
  # POST http://api.people.com:3000/people.xml
  #
  # when save is called on a new Person object.  An empty response is
  # is expected with a 'Location' header value:
  #
  # Response (201): Location: http://api.people.com:3000/people/2
  #
  ryan = Person.new(:first => 'Ryan')
  ryan.new?  #=> true
  ryan.save  #=> true
  ryan.new?  #=> false
  ryan.id    #=> 2

Update

‘save’ is also used to update an existing resource - and follows the same protocol as creating a resource with the exception that no response headers are needed - just an empty response when the update on the server side was successful.

  # <person><first>Ryan</first></person>
  #
  # is submitted as the body on
  #
  # PUT http://api.people.com:3000/people/1.xml
  #
  # when save is called on an existing Person object.  An empty response is
  # is expected with code (204)
  #
  ryan = Person.find(1)
  ryan.first #=> 'Ryan'
  ryan.first = 'Rizzle'
  ryan.save  #=> true

Delete

Destruction of a resource can be invoked as a class and instance method of the resource.

  # A request is made to
  #
  # DELETE http://api.people.com:3000/people/1.xml
  #
  # for both of these forms.  An empty response with
  # is expected with response code (200)
  #
  ryan = Person.find(1)
  ryan.destroy  #=> true
  ryan.exists?  #=> false
  Person.delete(2)  #=> true
  Person.exists?(2) #=> false

You can find more usage information in the ActiveResource::Base documentation.


Class: ActiveResource::Base

Class
ActiveResource::Base
In: | activeresource/lib/active_resource/base.rb
Parent: | Object

ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.

For an outline of what Active Resource is capable of, see files/README.html.

Automated mapping

Active Resource objects represent your RESTful resources as manipulatable Ruby objects. To map resources to Ruby objects, Active Resource only needs a class name that corresponds to the resource name (e.g., the class Person maps to the resources people, very similarly to Active Record) and a site value, which holds the URI of the resources.

    class Person < ActiveResource::Base
      self.site = "http://api.people.com:3000/"
    end

Now the Person class is mapped to RESTful resources located at api.people.com:3000/people/, and you can now use Active Resource‘s lifecycles methods to manipulate resources.

Lifecycle methods

Active Resource exposes methods for creating, finding, updating, and deleting resources from REST web services.

  ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
  ryan.save  #=> true
  ryan.id  #=> 2
  Person.exists?(ryan.id)  #=> true
  ryan.exists?  #=> true

  ryan = Person.find(1)
  # => Resource holding our newly create Person object

  ryan.first = 'Rizzle'
  ryan.save  #=> true

  ryan.destroy  #=> true

As you can see, these are very similar to Active Record‘s lifecycle methods for database records. You can read more about each of these methods in their respective documentation.

Custom REST methods

Since simple CRUD/lifecycle methods can‘t accomplish every task, Active Resource also supports defining your own custom REST methods.

  Person.new(:name => 'Ryan).post(:register)
  # => { :id => 1, :name => 'Ryan', :position => 'Clerk' }

  Person.find(1).put(:promote, :position => 'Manager')
  # => { :id => 1, :name => 'Ryan', :position => 'Manager' }

For more information on creating and using custom REST methods, see the ActiveResource::CustomMethods documentation.

Validations

You can validate resources client side by overriding validation methods in the base class.

    class Person < ActiveResource::Base
       self.site = "http://api.people.com:3000/"
       protected
         def validate
           errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
         end
    end

See the ActiveResource::Validations documentation for more information.

Authentication

Many REST APIs will require authentication, usually in the form of basic HTTP authentication. Authentication can be specified by putting the credentials in the site variable of the Active Resource class you need to authenticate.

  class Person < ActiveResource::Base
    self.site = "http://ryan:password@api.people.com:3000/"
  end

For obvious security reasons, it is probably best if such services are available over HTTPS.

Errors & Validation

Error handling and validation is handled in much the same manner as you‘re used to seeing in Active Record. Both the response code in the Http response and the body of the response are used to indicate that an error occurred.

Resource errors

When a get is requested for a resource that does not exist, the HTTP +404+ (Resource Not Found) response code will be returned from the server which will raise an ActiveResource::ResourceNotFound exception.

  # GET http://api.people.com:3000/people/999.xml
  ryan = Person.find(999) # => Raises ActiveResource::ResourceNotFound
  # => Response = 404

+404+ is just one of the HTTP error response codes that ActiveResource will handle with its own exception. The following HTTP response codes will also result in these exceptions:

200 - 399: | Valid response, no exception
404: | ActiveResource::ResourceNotFound
409: | ActiveResource::ResourceConflict
422: | ActiveResource::ResourceInvalid (rescued by save as validation errors)
401 - 499: | ActiveResource::ClientError
500 - 599: | ActiveResource::ServerError

These custom exceptions allow you to deal with resource errors more naturally and with more precision rather than returning a general HTTP error. For example:

  begin
    ryan = Person.find(my_id)
  rescue ActiveResource::ResourceNotFound
    redirect_to :action => 'not_found'
  rescue ActiveResource::ResourceConflict, ActiveResource::ResourceInvalid
    redirect_to :action => 'new'
  end

Validation errors

Active Resource supports validations on resources and will return errors if any these validations fail (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by a response code of +422+ and an XML representation of the validation errors. The save operation will then fail (with a false return value) and the validation errors can be accessed on the resource in question.

  ryan = Person.find(1)
  ryan.first #=> ''
  ryan.save  #=> false

  # When
  # PUT http://api.people.com:3000/people/1.xml
  # is requested with invalid values, the response is:
  #
  # Response (422):
  # <errors type="array"><error>First cannot be empty</error></errors>
  #

  ryan.errors.invalid?(:first)  #=> true
  ryan.errors.full_messages  #=> ['First cannot be empty']

Learn more about Active Resource‘s validation features in the ActiveResource::Validations documentation.

Methods
  • ==
  • collection_path
  • collection_path
  • connection
  • connection
  • create
  • create
  • delete
  • destroy
  • dup
  • element_path
  • element_path
  • eql?
  • exists?
  • exists?
  • find
  • format=
  • hash
  • headers
  • id
  • id=
  • id_from_response
  • load
  • load_attributes_from_response
  • new
  • new?
  • prefix
  • prefix=
  • prefix_source
  • reload
  • respond_to?
  • save
  • site
  • site=
  • to_param
  • to_xml
  • update
Public Class methods
collection_path(prefix_options = {}, query_options = nil)

Gets the collection path for the REST resources. If the query_options parameter is omitted, Rails will split from the prefix_options.

Options

prefix_options: | A hash to add a prefix to the request for nested URL‘s (e.g., :account_id => 19 would yield a URL like /accounts/19/purchases.xml).
query_options: | A hash to add items to the query string for the request.

Examples

  Post.collection_path
  # => /posts.xml

  Comment.collection_path(:post_id => 5)
  # => /posts/5/comments.xml

  Comment.collection_path(:post_id => 5, :active => 1)
  # => /posts/5/comments.xml?active=1

  Comment.collection_path({:post_id => 5}, {:active => 1})
  # => /posts/5/comments.xml?active=1

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 302
302:       def collection_path(prefix_options = {}, query_options = nil)
303:         prefix_options, query_options = split_options(prefix_options) if query_options.nil?
304:         "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
305:       end
connection(refresh = false)

An instance of ActiveResource::Connection that is the base connection to the remote service. The refresh parameter toggles whether or not the connection is refreshed at every request or not (defaults to false).

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 195
195:       def connection(refresh = false)
196:         if defined?(@connection) || superclass == Object
197:           @connection = Connection.new(site, format) if refresh || @connection.nil?
198:           @connection
199:         else
200:           superclass.connection
201:         end
202:       end
create(attributes = {})

Create a new resource instance and request to the remote service that it be saved, making it equivalent to the following simultaneous calls:

  ryan = Person.new(:first => 'ryan')
  ryan.save

The newly created resource is returned. If a failure has occurred an exception will be raised (see save). If the resource is invalid and has not been saved then valid? will return false, while new? will still return true.

Examples

  Person.create(:name => 'Jeremy', :email => 'myname@nospam.com', :enabled => true)
  my_person = Person.find(:first)
  my_person.email
  # => myname@nospam.com

  dhh = Person.create(:name => 'David', :email => 'dhh@nospam.com', :enabled => true)
  dhh.valid?
  # => true
  dhh.new?
  # => false

  # We'll assume that there's a validation that requires the name attribute
  that_guy = Person.create(:name => '', :email => 'thatguy@nospam.com', :enabled => true)
  that_guy.valid?
  # => false
  that_guy.new?
  # => true

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 339
339:       def create(attributes = {})
340:         returning(self.new(attributes)) { |res| res.save }
341:       end
delete(id, options = {})

Deletes the resources with the ID in the id parameter.

Options

All options specify prefix and query parameters.

Examples

  Event.delete(2)
  # => DELETE /events/2

  Event.create(:name => 'Free Concert', :location => 'Community Center')
  my_event = Event.find(:first)
  # => Events (id: 7)
  Event.delete(my_event.id)
  # => DELETE /events/7

  # Let's assume a request to events/5/cancel.xml
  Event.delete(params[:id])
  # => DELETE /events/5

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 412
412:       def delete(id, options = {})
413:         connection.delete(element_path(id, options))
414:       end
element_path(id, prefix_options = {}, query_options = nil)

Gets the element path for the given ID in id. If the query_options parameter is omitted, Rails will split from the prefix options.

Options

prefix_options: | A hash to add a prefix to the request for nested URL‘s (e.g., :account_id => 19 would yield a URL like /accounts/19/purchases.xml).
query_options: | A hash to add items to the query string for the request.

Examples

  Post.element_path(1)
  # => /posts/1.xml

  Comment.element_path(1, :post_id => 5)
  # => /posts/5/comments/1.xml

  Comment.element_path(1, :post_id => 5, :active => 1)
  # => /posts/5/comments/1.xml?active=1

  Comment.element_path(1, {:post_id => 5}, {:active => 1})
  # => /posts/5/comments/1.xml?active=1

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 276
276:       def element_path(id, prefix_options = {}, query_options = nil)
277:         prefix_options, query_options = split_options(prefix_options) if query_options.nil?
278:         "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
279:       end
exists?(id, options = {})

Asserts the existence of a resource, returning true if the resource is found.

Examples

  Note.create(:title => 'Hello, world.', :body => 'Nothing more for now...')
  Note.exists?(1)
  # => true

  Note.exists(1349)
  # => false

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 425
425:       def exists?(id, options = {})
426:         id && !find_single(id, options).nil?
427:       rescue ActiveResource::ResourceNotFound
428:         false
429:       end
find(*arguments)

Core method for finding resources. Used similarly to Active Record‘s find method.

Arguments

The first argument is considered to be the scope of the query. That is, how many resources are returned from the request. It can be one of the following.

+:one+: | Returns a single resource.
+:first+: | Returns the first resource found.
+:all+: | Returns every resource that matches the request.

Options

from: | Sets the path or custom method that resources will be fetched from.
params: | Sets query and prefix (nested URL) parameters.

Examples

  Person.find(1)
  # => GET /people/1.xml

  Person.find(:all)
  # => GET /people.xml

  Person.find(:all, :params => { :title => "CEO" })
  # => GET /people.xml?title=CEO

  Person.find(:first, :from => :managers)
  # => GET /people/managers.xml

  Person.find(:all, :from => "/companies/1/people.xml")
  # => GET /companies/1/people.xml

  Person.find(:one, :from => :leader)
  # => GET /people/leader.xml

  Person.find(:one, :from => "/companies/1/manager.xml")
  # => GET /companies/1/manager.xml

  StreetAddress.find(1, :params => { :person_id => 1 })
  # => GET /people/1/street_addresses/1.xml

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 381
381:       def find(*arguments)
382:         scope   = arguments.slice!(0)
383:         options = arguments.slice!(0) || {}
384:
385:         case scope
386:           when :all   then find_every(options)
387:           when :first then find_every(options).first
388:           when :one   then find_one(options)
389:           else             find_single(scope, options)
390:         end
391:       end
format=(mime_type_reference_or_format)

Sets the format that attributes are sent and received in from a mime type reference. Example:

  Person.format = :json
  Person.find(1) # => GET /people/1.json

  Person.format = ActiveResource::Formats::XmlFormat
  Person.find(1) # => GET /people/1.xml

Default format is :xml.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 179
179:       def format=(mime_type_reference_or_format)
180:         format = mime_type_reference_or_format.is_a?(Symbol) ?
181:           ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
182:
183:         write_inheritable_attribute("format", format)
184:         connection.format = format
185:       end
headers()

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 204
204:       def headers
205:         @headers ||= {}
206:       end
new(attributes = {})

Constructor method for new resources; the optional attributes parameter takes a Hash of attributes for the new resource.

Examples

  my_course = Course.new
  my_course.name = "Western Civilization"
  my_course.lecturer = "Don Trotter"
  my_course.save

  my_other_course = Course.new(:name => "Philosophy: Reason and Being", :lecturer => "Ralph Cling")
  my_other_course.save

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 519
519:     def initialize(attributes = {})
520:       @attributes     = {}
521:       @prefix_options = {}
522:       load(attributes)
523:     end
prefix(options={})

Gets the prefix for a resource‘s nested URL (e.g., prefix/collectionname/1.xml) This method is regenerated at runtime based on what the prefix is set to.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 217
217:       def prefix(options={})
218:         default = site.path
219:         default << '/' unless default[-1..-1] == '/'
220:         # generate the actual method based on the current site path
221:         self.prefix = default
222:         prefix(options)
223:       end
prefix=(value = '/')

Sets the prefix for a resource‘s nested URL (e.g., prefix/collectionname/1.xml). Default value is site.path.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 234
234:       def prefix=(value = '/')
235:         # Replace :placeholders with '#{embedded options[:lookups]}'
236:         prefix_call = value.gsub(/:\w+/) { |key| "\#{options[#{key}]}" }
237:
238:         # Redefine the new methods.
239:         code = "def prefix_source() \"\#{value}\" end\ndef prefix(options={}) \"\#{prefix_call}\" end\n"
240:         silence_warnings { instance_eval code, __FILE__, __LINE__ }
241:       rescue
242:         logger.error "Couldn't set prefix: #{$!}\n  #{code}"
243:         raise
244:       end
prefix_source()

An attribute reader for the source string for the resource path prefix. This method is regenerated at runtime based on what the prefix is set to.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 227
227:       def prefix_source
228:         prefix # generate #prefix and #prefix_source methods first
229:         prefix_source
230:       end
site()

Gets the URI of the REST resources to map for this class. The site variable is required ActiveResource‘s mapping to work.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 155
155:       def site
156:         if defined?(@site)
157:           @site
158:         elsif superclass != Object && superclass.site
159:           superclass.site.dup.freeze
160:         end
161:       end
site=(site)

Sets the URI of the REST resources to map for this class to the value in the site argument. The site variable is required ActiveResource‘s mapping to work.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 165
165:       def site=(site)
166:         @connection = nil
167:         @site = site.nil? ? nil : create_site_uri_from(site)
168:       end
Public Instance methods
==(other)

Test for equality. Resource are equal if and only if other is the same object or is an instance of the same class, is not +new?+, and has the same id.

Examples

  ryan = Person.create(:name => 'Ryan')
  jamie = Person.create(:name => 'Jamie')

  ryan == jamie
  # => false (Different name attribute and id)

  ryan_again = Person.new(:name => 'Ryan')
  ryan == ryan_again
  # => false (ryan_again is new?)

  ryans_clone = Person.create(:name => 'Ryan')
  ryan == ryans_clone
  # => false (Different id attributes)

  ryans_twin = Person.find(ryan.id)
  ryan == ryans_twin
  # => true

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 581
581:     def ==(other)
582:       other.equal?(self) || (other.instance_of?(self.class) && !other.new? && other.id == id)
583:     end
destroy()

Deletes the resource from the remote service.

Examples

  my_id = 3
  my_person = Person.find(my_id)
  my_person.destroy
  Person.find(my_id)
  # => 404 (Resource Not Found)

  new_person = Person.create(:name => 'James')
  new_id = new_person.id
  # => 7
  new_person.destroy
  Person.find(new_id)
  # => 404 (Resource Not Found)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 655
655:     def destroy
656:       connection.delete(element_path, self.class.headers)
657:     end
dup()

Duplicate the current resource without saving it.

Examples

  my_invoice = Invoice.create(:customer => 'That Company')
  next_invoice = my_invoice.dup
  next_invoice.new?
  # => true

  next_invoice.save
  next_invoice == my_invoice
  # => false (different id attributes)

  my_invoice.customer
  # => That Company
  next_invoice.customer
  # => That Company

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 612
612:     def dup
613:       returning self.class.new do |resource|
614:         resource.attributes     = @attributes
615:         resource.prefix_options = @prefix_options
616:       end
617:     end
eql?(other)

Tests for equality (delegates to ==).

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 586
586:     def eql?(other)
587:       self == other
588:     end
exists?()

Evaluates to true if this resource is not +new?+ and is found on the remote service. Using this method, you can check for resources that may have been deleted between the object‘s instantiation and actions on it.

Examples

  Person.create(:name => 'Theodore Roosevelt')
  that_guy = Person.find(:first)
  that_guy.exists?
  # => true

  that_lady = Person.new(:name => 'Paul Bean')
  that_lady.exists?
  # => false

  guys_id = that_guy.id
  Person.delete(guys_id)
  that_guy.exists?
  # => false

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 678
678:     def exists?
679:       !new? && self.class.exists?(id, :params => prefix_options)
680:     end
hash()

Delegates to id in order to allow two resources of the same type and id to work with something like:

  [Person.find(1), Person.find(2)] & [Person.find(1), Person.find(4)] # => [Person.find(1)]

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 592
592:     def hash
593:       id.hash
594:     end
id()

Get the id attribute of the resource.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 545
545:     def id
546:       attributes[self.class.primary_key]
547:     end
id=(id)

Set the id attribute of the resource.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 550
550:     def id=(id)
551:       attributes[self.class.primary_key] = id
552:     end
load(attributes)

A method to manually load attributes from a hash. Recursively loads collections of resources. This method is called in initialize and create when a Hash of attributes is provided.

Examples

  my_attrs = {:name => 'J&J Textiles', :industry => 'Cloth and textiles'}

  the_supplier = Supplier.find(:first)
  the_supplier.name
  # => 'J&M Textiles'
  the_supplier.load(my_attrs)
  the_supplier.name('J&J Textiles')

  # These two calls are the same as Supplier.new(my_attrs)
  my_supplier = Supplier.new
  my_supplier.load(my_attrs)

  # These three calls are the same as Supplier.create(my_attrs)
  your_supplier = Supplier.new
  your_supplier.load(my_attrs)
  your_supplier.save

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 750
750:     def load(attributes)
751:       raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
752:       @prefix_options, attributes = split_options(attributes)
753:       attributes.each do |key, value|
754:         @attributes[key.to_s] =
755:           case value
756:             when Array
757:               resource = find_or_create_resource_for_collection(key)
758:               value.map { |attrs| resource.new(attrs) }
759:             when Hash
760:               resource = find_or_create_resource_for(key)
761:               resource.new(value)
762:             else
763:               value.dup rescue value
764:           end
765:       end
766:       self
767:     end
new?()

A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).

Examples

  not_new = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
  not_new.new?
  # => false

  is_new = Computer.new(:brand => 'IBM', :make => 'Thinkpad', :vendor => 'IBM')
  is_new.new?
  # => true

  is_new.save
  is_new.new?
  # => false

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 540
540:     def new?
541:       id.nil?
542:     end
reload()

A method to reload the attributes of this object from the remote web service.

Examples

  my_branch = Branch.find(:first)
  my_branch.name
  # => Wislon Raod

  # Another client fixes the typo...

  my_branch.name
  # => Wislon Raod
  my_branch.reload
  my_branch.name
  # => Wilson Road

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 725
725:     def reload
726:       self.load(self.class.find(id, :params => @prefix_options).attributes)
727:     end
respond_to?(method, include_priv = false)

A method to determine if an object responds to a message (e.g., a method call). In Active Resource, a Person object with a name attribute can answer true to +my_person.respond_to?("name")+, +my_person.respond_to?("name=")+, and +my_person.respond_to?("name?")+.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 775
775:     def respond_to?(method, include_priv = false)
776:       method_name = method.to_s
777:       if attributes.nil?
778:         return super
779:       elsif attributes.has_key?(method_name)
780:         return true
781:       elsif ['?','='].include?(method_name.last) && attributes.has_key?(method_name.first(-1))
782:         return true
783:       end
784:       # super must be called at the end of the method, because the inherited respond_to?
785:       # would return true for generated readers, even if the attribute wasn't present
786:       super
787:     end
save()

A method to save (POST) or update (PUT) a resource. It delegates to create if a new object, update if it is existing. If the response to the save includes a body, it will be assumed that this body is XML for the final object as it looked after the save (which would include attributes like created_at that weren‘t part of the original submit).

Examples

  my_company = Company.new(:name => 'RoleModel Software', :owner => 'Ken Auer', :size => 2)
  my_company.new?
  # => true
  my_company.save
  # => POST /companies/ (create)

  my_company.new?
  # => false
  my_company.size = 10
  my_company.save
  # => PUT /companies/1 (update)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 636
636:     def save
637:       new? ? create : update
638:     end
to_param()

Allows ActiveResource objects to be used as parameters in ActionPack URL generation.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 555
555:     def to_param
556:       id && id.to_s
557:     end
to_xml(options={})

A method to convert the the resource to an XML string.

Options

The options parameter is handed off to the to_xml method on each attribute, so it has the same options as the to_xml methods in ActiveSupport.

indent: | Set the indent level for the XML output (default is +2+).
dasherize: | Boolean option to determine whether or not element names should replace underscores with dashes (default is false).
skip_instruct: | Toggle skipping the +instruct!+ call on the XML builder that generates the XML declaration (default is false).

Examples

  my_group = SubsidiaryGroup.find(:first)
  my_group.to_xml
  # => <?xml version="1.0" encoding="UTF-8"?>
  #    <subsidiary_group> [...] </subsidiary_group>

  my_group.to_xml(:dasherize => true)
  # => <?xml version="1.0" encoding="UTF-8"?>
  #    <subsidiary-group> [...] </subsidiary-group>

  my_group.to_xml(:skip_instruct => true)
  # => <subsidiary_group> [...] </subsidiary_group>

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 707
707:     def to_xml(options={})
708:       attributes.to_xml({:root => self.class.element_name}.merge(options))
709:     end
Protected Instance methods
collection_path(options = nil)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 825
825:       def collection_path(options = nil)
826:         self.class.collection_path(options || prefix_options)
827:       end
connection(refresh = false)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 791
791:       def connection(refresh = false)
792:         self.class.connection(refresh)
793:       end
create()

Create (i.e., save to the remote service) the new resource.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 803
803:       def create
804:         returning connection.post(collection_path, to_xml, self.class.headers) do |response|
805:           self.id = id_from_response(response)
806:           load_attributes_from_response(response)
807:         end
808:       end
element_path(options = nil)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 821
821:       def element_path(options = nil)
822:         self.class.element_path(id, options || prefix_options)
823:       end
id_from_response(response)

Takes a response from a typical create post and pulls the ID out

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 817
817:       def id_from_response(response)
818:         response['Location'][/\/([^\/]*?)(\.\w+)?$/, 1]
819:       end
load_attributes_from_response(response)

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 810
810:       def load_attributes_from_response(response)
811:         if response['Content-Length'] != "0" && response.body.strip.size > 0
812:           load(self.class.format.decode(response.body))
813:         end
814:       end
update()

Update the resource on the remote service.

[ show source ]

     # File activeresource/lib/active_resource/base.rb, line 796
796:       def update
797:         returning connection.put(element_path(prefix_options), to_xml, self.class.headers) do |response|
798:           load_attributes_from_response(response)
799:         end
800:       end


Class: ActiveResource::BadRequest

Class
ActiveResource::BadRequest
In: | activeresource/lib/active_resource/connection.rb
Parent: | ClientError

400 Bad Request


Class: ActiveResource::ClientError

Class
ActiveResource::ClientError
In: | activeresource/lib/active_resource/connection.rb
Parent: | ConnectionError

4xx Client Error


Class: ActiveResource::Connection

Class
ActiveResource::Connection
In: | activeresource/lib/active_resource/connection.rb activeresource/lib/active_resource/http_mock.rb
Parent: | Object

Class to handle connections to remote web services. This class is used by ActiveResource::Base to interface with REST services.

Methods
  • delete
  • get
  • new
  • post
  • put
  • requests
  • site=
Attributes
[RW] | format
[R] | site
Public Class methods
new(site, format = ActiveResource::Formats[:xml])

The site parameter is required and will set the site attribute to the URI for the remote resource service.

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 69
69:     def initialize(site, format = ActiveResource::Formats[:xml])
70:       raise ArgumentError, 'Missing site URI' unless site
71:       self.site = site
72:       self.format = format
73:     end
requests()

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 62
62:       def requests
63:         @@requests ||= []
64:       end
Public Instance methods
delete(path, headers = {})

Execute a DELETE request (see HTTP protocol documentation if unfamiliar). Used to delete resources.

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 88
88:     def delete(path, headers = {})
89:       request(:delete, path, build_request_headers(headers))
90:     end
get(path, headers = {})

Execute a GET request. Used to get (find) resources.

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 82
82:     def get(path, headers = {})
83:       format.decode(request(:get, path, build_request_headers(headers)).body)
84:     end
post(path, body = '', headers = {})

Execute a POST request. Used to create new resources.

[ show source ]

     # File activeresource/lib/active_resource/connection.rb, line 100
100:     def post(path, body = '', headers = {})
101:       request(:post, path, body.to_s, build_request_headers(headers))
102:     end
put(path, body = '', headers = {})

Execute a PUT request (see HTTP protocol documentation if unfamiliar). Used to update resources.

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 94
94:     def put(path, body = '', headers = {})
95:       request(:put, path, body.to_s, build_request_headers(headers))
96:     end
site=(site)

Set URI for remote service.

[ show source ]

    # File activeresource/lib/active_resource/connection.rb, line 76
76:     def site=(site)
77:       @site = site.is_a?(URI) ? site : URI.parse(site)
78:     end


Module: ActiveResource::CustomMethods

Module
ActiveResource::CustomMethods
In: activeresource/lib/active_resource/custom_methods.rb
Methods
  • delete
  • get
  • included
  • post
  • put
Included Modules
  • ActiveResource::CustomMethods::InstanceMethods
Classes and Modules
Module ActiveResource::CustomMethods::ClassMethods
Module ActiveResource::CustomMethods::InstanceMethods
Public Class methods
delete(custom_method_name, options = {})

Need to jump through some hoops to retain the original class ‘delete’ method

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 55
55:           def delete(custom_method_name, options = {})
56:             if (custom_method_name.is_a?(Symbol))
57:               connection.delete(custom_method_collection_url(custom_method_name, options), headers)
58:             else
59:               orig_delete(custom_method_name, options)
60:             end
61:           end
get(method_name, options = {})

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 42
42:           def get(method_name, options = {})
43:             connection.get(custom_method_collection_url(method_name, options), headers)
44:           end
included(within)

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 34
34:     def self.included(within)
35:       within.class_eval do
36:         extend ActiveResource::CustomMethods::ClassMethods
37:         include ActiveResource::CustomMethods::InstanceMethods
38:
39:         class << self
40:           alias :orig_delete :delete
41:
42:           def get(method_name, options = {})
43:             connection.get(custom_method_collection_url(method_name, options), headers)
44:           end
45:
46:           def post(method_name, options = {}, body = '')
47:             connection.post(custom_method_collection_url(method_name, options), body, headers)
48:           end
49:
50:           def put(method_name, options = {}, body = '')
51:             connection.put(custom_method_collection_url(method_name, options), body, headers)
52:           end
53:
54:           # Need to jump through some hoops to retain the original class 'delete' method
55:           def delete(custom_method_name, options = {})
56:             if (custom_method_name.is_a?(Symbol))
57:               connection.delete(custom_method_collection_url(custom_method_name, options), headers)
58:             else
59:               orig_delete(custom_method_name, options)
60:             end
61:           end
62:         end
63:       end
64:     end
post(method_name, options = {}, body = '')

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 46
46:           def post(method_name, options = {}, body = '')
47:             connection.post(custom_method_collection_url(method_name, options), body, headers)
48:           end
put(method_name, options = {}, body = '')

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 50
50:           def put(method_name, options = {}, body = '')
51:             connection.put(custom_method_collection_url(method_name, options), body, headers)
52:           end


Module: ActiveResource::CustomMethods::ClassMethods

Module
ActiveResource::CustomMethods::ClassMethods
In: activeresource/lib/active_resource/custom_methods.rb
Methods
  • custom_method_collection_url
Public Instance methods
custom_method_collection_url(method_name, options = {})

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 67
67:       def custom_method_collection_url(method_name, options = {})
68:         prefix_options, query_options = split_options(options)
69:         "#{prefix(prefix_options)}#{collection_name}/#{method_name}.xml#{query_string(query_options)}"
70:       end


Module: ActiveResource::CustomMethods::InstanceMethods

Module
ActiveResource::CustomMethods::InstanceMethods
In: activeresource/lib/active_resource/custom_methods.rb
Methods
  • delete
  • get
  • post
  • put
Public Instance methods
delete(method_name, options = {})

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 90
90:       def delete(method_name, options = {})
91:         connection.delete(custom_method_element_url(method_name, options), self.class.headers)
92:       end
get(method_name, options = {})

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 74
74:       def get(method_name, options = {})
75:         connection.get(custom_method_element_url(method_name, options), self.class.headers)
76:       end
post(method_name, options = {}, body = '')

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 78
78:       def post(method_name, options = {}, body = '')
79:         if new?
80:           connection.post(custom_method_new_element_url(method_name, options), (body.nil? ? to_xml : body), self.class.headers)
81:         else
82:           connection.post(custom_method_element_url(method_name, options), body, self.class.headers)
83:         end
84:       end
put(method_name, options = {}, body = '')

[ show source ]

    # File activeresource/lib/active_resource/custom_methods.rb, line 86
86:       def put(method_name, options = {}, body = '')
87:         connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
88:       end


Class: ActiveResource::Errors

Class
ActiveResource::Errors
In: | activeresource/lib/active_resource/validations.rb
Parent: | Object

Active Resource validation is reported to and from this object, which is used by Base#save to determine whether the object in a valid state to be saved. See usage example in Validations.

Methods
  • []
  • add
  • add_to_base
  • clear
  • count
  • each
  • each_full
  • from_xml
  • full_messages
  • invalid?
  • length
  • on
  • on_base
  • size
Included Modules
  • Enumerable
Attributes
[R] errors
Public Instance methods
[](attribute)

Alias for on

add(attribute, msg)

Adds an error to an Active Resource object‘s attribute (named for the attribute parameter) with the error message in msg.

Examples

  my_resource = Node.find(1)
  my_resource.errors.add('name', 'can not be "base"') if my_resource.name == 'base'
  my_resource.errors.on('name')
  # => 'can not be "base"!'

  my_resource.errors.add('desc', 'can not be blank') if my_resource.desc == ''
  my_resource.valid?
  # => false
  my_resource.errors.on('desc')
  # => 'can not be blank!'

[ show source ]

    # File activeresource/lib/active_resource/validations.rb, line 50
50:     def add(attribute, msg)
51:       @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
52:       @errors[attribute.to_s] << msg
53:     end
add_to_base(msg)

Add an error to the base Active Resource object rather than an attribute.

Examples

  my_folder = Folder.find(1)
  my_folder.errors.add_to_base("You can't edit an existing folder")
  my_folder.errors.on_base
  # => "You can't edit an existing folder"

  my_folder.errors.add_to_base("This folder has been tagged as frozen")
  my_folder.valid?
  # => false
  my_folder.errors.on_base
  # => ["You can't edit an existing folder", "This folder has been tagged as frozen"]

[ show source ]

    # File activeresource/lib/active_resource/validations.rb, line 31
31:     def add_to_base(msg)
32:       add(:base, msg)
33:     end
clear()

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 178
178:     def clear
179:       @errors = {}
180:     end
count()

Alias for size

each() {|attr, msg| ...}

Yields each attribute and associated message per error added.

Examples

  my_person = Person.new(params[:person])

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.errors.add('password', 'can not be empty') if my_person.password == ''
  messages = ''
  my_person.errors.each {|attr, msg| messages += attr.humanize + " " + msg + "<br />"}
  messages
  # => "Login can not be empty<br />Password can not be empty<br />"

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 128
128:     def each
129:       @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
130:     end
each_full() {|msg| ...}

Yields each full error message added. So Person.errors.add("first_name", "can‘t be empty") will be returned through iteration as "First name can‘t be empty".

Examples

  my_person = Person.new(params[:person])

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.errors.add('password', 'can not be empty') if my_person.password == ''
  messages = ''
  my_person.errors.each_full {|msg| messages += msg + "<br/>"}
  messages
  # => "Login can not be empty<br />Password can not be empty<br />"

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 145
145:     def each_full
146:       full_messages.each { |msg| yield msg }
147:     end
from_xml(xml)

Grabs errors from the XML response.

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 203
203:     def from_xml(xml)
204:       clear
205:       humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
206:       messages = Hash.from_xml(xml)['errors']['error'] rescue []
207:       messages.each do |message|
208:         attr_message = humanized_attributes.keys.detect do |attr_name|
209:           if message[0, attr_name.size + 1] == "#{attr_name} "
210:             add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
211:           end
212:         end
213:
214:         add_to_base message if attr_message.nil?
215:       end
216:     end
full_messages()

Returns all the full error messages in an array.

Examples

  my_person = Person.new(params[:person])

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.errors.add('password', 'can not be empty') if my_person.password == ''
  messages = ''
  my_person.errors.full_messages.each {|msg| messages += msg + "<br/>"}
  messages
  # => "Login can not be empty<br />Password can not be empty<br />"

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 161
161:     def full_messages
162:       full_messages = []
163:
164:       @errors.each_key do |attr|
165:         @errors[attr].each do |msg|
166:           next if msg.nil?
167:
168:           if attr == "base"
169:             full_messages << msg
170:           else
171:             full_messages << [attr.humanize, msg].join(' ')
172:           end
173:         end
174:       end
175:       full_messages
176:     end
invalid?(attribute)

Returns true if the specified attribute has errors associated with it.

Examples

  my_resource = Disk.find(1)
  my_resource.errors.add('location', 'must be Main') unless my_resource.location == 'Main'
  my_resource.errors.on('location')
  # => 'must be Main!'

  my_resource.errors.invalid?('location')
  # => true
  my_resource.errors.invalid?('name')
  # => false

[ show source ]

    # File activeresource/lib/active_resource/validations.rb, line 67
67:     def invalid?(attribute)
68:       !@errors[attribute.to_s].nil?
69:     end
length()

Alias for size

on(attribute)

A method to return the errors associated with attribute, which returns nil, if no errors are associated with the specified attribute, the error message if one error is associated with the specified attribute, or an array of error messages if more than one error is associated with the specified attribute.

Examples

  my_person = Person.new(params[:person])
  my_person.errors.on('login')
  # => nil

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.errors.on('login')
  # => 'can not be empty'

  my_person.errors.add('login', 'can not be longer than 10 characters') if my_person.login.length > 10
  my_person.errors.on('login')
  # => ['can not be empty', 'can not be longer than 10 characters']
This method is also aliased as []

[ show source ]

    # File activeresource/lib/active_resource/validations.rb, line 87
87:     def on(attribute)
88:       errors = @errors[attribute.to_s]
89:       return nil if errors.nil?
90:       errors.size == 1 ? errors.first : errors
91:     end
on_base()

A method to return errors assigned to base object through add_to_base, which returns nil, if no errors are associated with the specified attribute, the error message if one error is associated with the specified attribute, or an array of error messages if more than one error is associated with the specified attribute.

Examples

  my_account = Account.find(1)
  my_account.errors.on_base
  # => nil

  my_account.errors.add_to_base("This account is frozen")
  my_account.errors.on_base
  # => "This account is frozen"

  my_account.errors.add_to_base("This account has been closed")
  my_account.errors.on_base
  # => ["This account is frozen", "This account has been closed"]

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 112
112:     def on_base
113:       on(:base)
114:     end
size()

Returns the total number of errors added. Two errors added to the same attribute will be counted as such with this as well.

Examples

  my_person = Person.new(params[:person])
  my_person.errors.size
  # => 0

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.errors.add('password', 'can not be empty') if my_person.password == ''
  my_person.error.size
  # => 2
This method is also aliased as count length

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 195
195:     def size
196:       @errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
197:     end


Class: ActiveResource::ForbiddenAccess

Class
ActiveResource::ForbiddenAccess
In: | activeresource/lib/active_resource/connection.rb
Parent: | ClientError

403 Forbidden


Module: ActiveResource::Formats

Module
ActiveResource::Formats
In: activeresource/lib/active_resource/formats/json_format.rb activeresource/lib/active_resource/formats/xml_format.rb activeresource/lib/active_resource/formats.rb
Methods
  • []
Classes and Modules
Module ActiveResource::Formats::JsonFormat
Module ActiveResource::Formats::XmlFormat
Public Class methods
[](mime_type_reference)

Lookup the format class from a mime type reference symbol. Example:

  ActiveResource::Formats[:xml]  # => ActiveResource::Formats::XmlFormat
  ActiveResource::Formats[:json] # => ActiveResource::Formats::JsonFormat

[ show source ]

   # File activeresource/lib/active_resource/formats.rb, line 7
7:     def self.[](mime_type_reference)
8:       ActiveResource::Formats.const_get(mime_type_reference.to_s.camelize + "Format")
9:     end


Module: ActiveResource::Formats::JsonFormat

Module
ActiveResource::Formats::JsonFormat
In: activeresource/lib/active_resource/formats/json_format.rb
Methods
  • decode
  • encode
  • extension
  • mime_type
Public Instance methods
decode(json)

[ show source ]

    # File activeresource/lib/active_resource/formats/json_format.rb, line 18
18:       def decode(json)
19:         ActiveSupport::JSON.decode(json)
20:       end
encode(hash)

[ show source ]

    # File activeresource/lib/active_resource/formats/json_format.rb, line 14
14:       def encode(hash)
15:         hash.to_json
16:       end
extension()

[ show source ]

   # File activeresource/lib/active_resource/formats/json_format.rb, line 6
6:       def extension
7:         "json"
8:       end
mime_type()

[ show source ]

    # File activeresource/lib/active_resource/formats/json_format.rb, line 10
10:       def mime_type
11:         "application/json"
12:       end


Module: ActiveResource::Formats::XmlFormat

Module
ActiveResource::Formats::XmlFormat
In: activeresource/lib/active_resource/formats/xml_format.rb
Methods
  • decode
  • encode
  • extension
  • mime_type
Public Instance methods
decode(xml)

[ show source ]

    # File activeresource/lib/active_resource/formats/xml_format.rb, line 18
18:       def decode(xml)
19:         from_xml_data(Hash.from_xml(xml))
20:       end
encode(hash)

[ show source ]

    # File activeresource/lib/active_resource/formats/xml_format.rb, line 14
14:       def encode(hash)
15:         hash.to_xml
16:       end
extension()

[ show source ]

   # File activeresource/lib/active_resource/formats/xml_format.rb, line 6
6:       def extension
7:         "xml"
8:       end
mime_type()

[ show source ]

    # File activeresource/lib/active_resource/formats/xml_format.rb, line 10
10:       def mime_type
11:         "application/xml"
12:       end


Class: ActiveResource::HttpMock

Class
ActiveResource::HttpMock
In: | activeresource/lib/active_resource/http_mock.rb
Parent: | Object
Methods
  • new
  • requests
  • reset!
  • respond_to
  • responses
Classes and Modules
Class ActiveResource::HttpMock::Responder
Public Class methods
new(site)

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 72
72:     def initialize(site)
73:       @site = site
74:     end
requests()

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 23
23:       def requests
24:         @@requests ||= []
25:       end
reset!()

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 44
44:       def reset!
45:         requests.clear
46:         responses.clear
47:       end
respond_to(pairs = {}) {|Responder.new(responses)| ...}

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 31
31:       def respond_to(pairs = {})
32:         reset!
33:         pairs.each do |(path, response)|
34:           responses[path] = response
35:         end
36:
37:         if block_given?
38:           yield Responder.new(responses)
39:         else
40:           Responder.new(responses)
41:         end
42:       end
responses()

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 27
27:       def responses
28:         @@responses ||= {}
29:       end


Class: ActiveResource::HttpMock::Responder

Class
ActiveResource::HttpMock::Responder
In: | activeresource/lib/active_resource/http_mock.rb
Parent: | Object
Methods
  • new
Public Class methods
new(responses)

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 8
 8:       def initialize(responses)
 9:         @responses = responses
10:       end


Class: ActiveResource::InvalidRequestError

Class
ActiveResource::InvalidRequestError
In: | activeresource/lib/active_resource/http_mock.rb
Parent: | StandardError


Class: ActiveResource::Request

Class
ActiveResource::Request
In: | activeresource/lib/active_resource/http_mock.rb
Parent: | Object
Methods
  • ==
  • eql?
  • hash
  • new
  • to_s
Attributes
[RW] | body
[RW] | headers
[RW] | method
[RW] | path
Public Class methods
new(method, path, body = nil, headers = {})

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 80
80:     def initialize(method, path, body = nil, headers = {})
81:       @method, @path, @body, @headers = method, path, body, headers.dup
82:       @headers.update('Content-Type' => 'application/xml')
83:     end
Public Instance methods
==(other_request)

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 85
85:     def ==(other_request)
86:       other_request.hash == hash
87:     end
eql?(other_request)

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 89
89:     def eql?(other_request)
90:       self == other_request
91:     end
hash()

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 97
97:     def hash
98:       "#{path}#{method}#{headers}".hash
99:     end
to_s()

[ show source ]

    # File activeresource/lib/active_resource/http_mock.rb, line 93
93:     def to_s
94:       "<#{method.to_s.upcase}: #{path} [#{headers}] (#{body})>"
95:     end


Class: ActiveResource::ResourceConflict

Class
ActiveResource::ResourceConflict
In: | activeresource/lib/active_resource/connection.rb
Parent: | ClientError

409 Conflict


Class: ActiveResource::ResourceNotFound

Class
ActiveResource::ResourceNotFound
In: | activeresource/lib/active_resource/connection.rb
Parent: | ClientError

404 Not Found


Class: ActiveResource::Response

Class
ActiveResource::Response
In: | activeresource/lib/active_resource/http_mock.rb
Parent: | Object
Methods
  • ==
  • []
  • []=
  • new
  • success?
Attributes
[RW] | body
[RW] | code
[RW] | headers
[RW] | message
Public Class methods
new(body, message = 200, headers = {})

[ show source ]

     # File activeresource/lib/active_resource/http_mock.rb, line 105
105:     def initialize(body, message = 200, headers = {})
106:       @body, @message, @headers = body, message.to_s, headers
107:       @code = @message[0,3].to_i
108:
109:       resp_cls = Net::HTTPResponse::CODE_TO_OBJ[@code.to_s]
110:       if resp_cls && !resp_cls.body_permitted?
111:         @body = nil
112:       end
113:
114:       if @body.nil?
115:         self['Content-Length'] = "0"
116:       else
117:         self['Content-Length'] = body.size.to_s
118:       end
119:     end
Public Instance methods
==(other)

[ show source ]

     # File activeresource/lib/active_resource/http_mock.rb, line 133
133:     def ==(other)
134:       if (other.is_a?(Response))
135:         other.body == body && other.message == message && other.headers == headers
136:       else
137:         false
138:       end
139:     end
[](key)

[ show source ]

     # File activeresource/lib/active_resource/http_mock.rb, line 125
125:     def [](key)
126:       headers[key]
127:     end
[]=(key, value)

[ show source ]

     # File activeresource/lib/active_resource/http_mock.rb, line 129
129:     def []=(key, value)
130:       headers[key] = value
131:     end
success?()

[ show source ]

     # File activeresource/lib/active_resource/http_mock.rb, line 121
121:     def success?
122:       (200..299).include?(code)
123:     end


Class: ActiveResource::ServerError

Class
ActiveResource::ServerError
In: | activeresource/lib/active_resource/connection.rb
Parent: | ConnectionError

5xx Server Error


Class: ActiveResource::UnauthorizedAccess

Class
ActiveResource::UnauthorizedAccess
In: | activeresource/lib/active_resource/connection.rb
Parent: | ClientError

401 Unauthorized


Module: ActiveResource::Validations

Module
ActiveResource::Validations
In: activeresource/lib/active_resource/validations.rb

Module to allow validation of ActiveResource objects, which creates an Errors instance for every resource. Methods are implemented by overriding +Base#validate+ or its variants Each of these methods can inspect the state of the object, which usually means ensuring that a number of attributes have a certain value (such as not empty, within a given range, matching a certain regular expression and so on).

Example

  class Person < ActiveResource::Base
     self.site = "http://www.localhost.com:3000/"
     protected
       def validate
         errors.add_on_empty %w( first_name last_name )
         errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
       end

       def validate_on_create # is only run the first time a new object is saved
         unless valid_member?(self)
           errors.add("membership_discount", "has expired")
         end
       end

       def validate_on_update
         errors.add_to_base("No changes have occurred") if unchanged_attributes?
       end
  end

  person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.")
  person.save                         # => false (and doesn't do the save)
  person.errors.empty?                # => false
  person.errors.count                 # => 2
  person.errors.on "last_name"        # => "can't be empty"
  person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" }
  person.save                         # => true (and person is now saved to the remote service)
Methods
  • errors
  • save_with_validation
  • valid?
Public Instance methods
errors()

Returns the Errors object that holds all information about attribute error messages.

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 284
284:     def errors
285:       @errors ||= Errors.new(self)
286:     end
save_with_validation()

Validate a resource and save (POST) it to the remote web service.

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 261
261:     def save_with_validation
262:       save_without_validation
263:       true
264:     rescue ResourceInvalid => error
265:       errors.from_xml(error.response.body)
266:       false
267:     end
valid?()

Checks for errors on an object (i.e., is resource.errors empty?).

Examples

  my_person = Person.create(params[:person])
  my_person.valid?
  # => true

  my_person.errors.add('login', 'can not be empty') if my_person.login == ''
  my_person.valid?
  # => false

[ show source ]

     # File activeresource/lib/active_resource/validations.rb, line 279
279:     def valid?
280:       errors.empty?
281:     end


File: base.rb

File
base.rb
Path: | activeresource/lib/active_resource/base.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008

Required Files
  • active_resource/connection
  • cgi
  • set


File: connection.rb

File
connection.rb
Path: | activeresource/lib/active_resource/connection.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008

Required Files
  • net/https
  • date
  • time
  • uri
  • benchmark


File: custom_methods.rb

File
custom_methods.rb
Path: | activeresource/lib/active_resource/custom_methods.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008

A module to support custom REST methods and sub-resources, allowing you to break out of the "default" REST methods with your own custom resource requests. For example, say you use Rails to expose a REST service and configure your routes with:

   map.resources :people, :new => { :register => :post },
                          :element => { :promote => :put, :deactivate => :delete }
                          :collection => { :active => :get }

 This route set creates routes for the following http requests:

   POST    /people/new/register.xml #=> PeopleController.register
   PUT     /people/1/promote.xml    #=> PeopleController.promote with :id => 1
   DELETE  /people/1/deactivate.xml #=> PeopleController.deactivate with :id => 1
   GET     /people/active.xml       #=> PeopleController.active

Using this module, Active Resource can use these custom REST methods just like the standard methods.

  class Person < ActiveResource::Base
    self.site = "http://37s.sunrise.i:3000"
  end

  Person.new(:name => 'Ryan).post(:register)  # POST /people/new/register.xml
  # => { :id => 1, :name => 'Ryan' }

  Person.find(1).put(:promote, :position => 'Manager') # PUT /people/1/promote.xml
  Person.find(1).delete(:deactivate) # DELETE /people/1/deactivate.xml

  Person.get(:active)  # GET /people/active.xml
  # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]


File: formats.rb

File
formats.rb
Path: | activeresource/lib/active_resource/formats.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008

Required Files
  • active_resource/formats/xml_format
  • active_resource/formats/json_format


File: json_format.rb

File
json_format.rb
Path: | activeresource/lib/active_resource/formats/json_format.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008


File: xml_format.rb

File
xml_format.rb
Path: | activeresource/lib/active_resource/formats/xml_format.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008


File: http_mock.rb

File
http_mock.rb
Path: | activeresource/lib/active_resource/http_mock.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008

Required Files
  • active_resource/connection


File: validations.rb

File
validations.rb
Path: | activeresource/lib/active_resource/validations.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008


File: version.rb

File
version.rb
Path: | activeresource/lib/active_resource/version.rb
Modified: | Sun Mar 02 11:09:08 -0700 2008


File: CHANGELOG

File
CHANGELOG
Path: | activeresource/CHANGELOG
Modified: | Sun Mar 02 11:09:08 -0700 2008

*2.0.2* (December 16th, 2007)

  • Added more specific exceptions for 400, 401, and 403 (all descending from ClientError so existing rescues will work) 10326 [trek]
  • Correct empty response handling. 10445 [seangeo]

*2.0.1* (December 7th, 2007)

  • Don‘t cache net/http object so that ActiveResource is more thread-safe. Closes 10142 [kou]
  • Update XML documentation examples to include explicit type attributes. Closes 9754 [hasmanyjosh]
  • Added one-off declarations of mock behavior [DHH]. Example:
      Before:
    ActiveResource::HttpMock.respond_to do |mock|
      mock.get "/people/1.xml", {}, "<person><name>David</name></person>"
    end

  Now:
    ActiveResource::HttpMock.respond_to.get "/people/1.xml", {}, "<person><name>David</name></person>"
  • Added ActiveResource.format= which defaults to :xml but can also be set to :json [DHH]. Example:
      class Person < ActiveResource::Base
    self.site   = "http://app/"
    self.format = :json
  end

  person = Person.find(1) # => GET http://app/people/1.json
  person.name = "David"
  person.save             # => PUT http://app/people/1.json {name: "David"}

  Person.format = :xml
  person.name = "Mary"
  person.save             # => PUT http://app/people/1.json <person><name>Mary</name></person>
  • Fix reload error when path prefix is used. 8727 [Ian Warshak]
  • Remove ActiveResource::Struct because it hasn‘t proven very useful. Creating a new ActiveResource::Base subclass is often less code and always clearer. 8612 [Josh Peek]
  • Fix query methods on resources. [Cody Fauser]
  • pass the prefix_options to the instantiated record when using find without a specific id. Closes 8544 [alloy]
  • Recognize and raise an exception on 405 Method Not Allowed responses. 7692 [Josh Peek]
  • Handle string and symbol param keys when splitting params into prefix params and query params.
      Comment.find(:all, :params => { :article_id => 5, :page => 2 }) or Comment.find(:all, :params => { 'article_id' => 5, :page => 2 })
  • Added find-one with symbol [DHH]. Example: Person.find(:one, :from => :leader) # => GET /people/leader.xml
  • BACKWARDS INCOMPATIBLE: Changed the finder API to be more extensible with :params and more strict usage of scopes [DHH]. Changes:
      Person.find(:all, :title => "CEO")      ...becomes: Person.find(:all, :params => { :title => "CEO" })
  Person.find(:managers)                  ...becomes: Person.find(:all, :from => :managers)
  Person.find("/companies/1/manager.xml") ...becomes: Person.find(:one, :from => "/companies/1/manager.xml")
  • Add support for setting custom headers per Active Resource model [Rick]

    class Project

      headers['X-Token'] = 'foo'

    end

    # makes the GET request with the custom X-Token header Project.find(:all)

  • Added find-by-path options to ActiveResource::Base.find [DHH]. Examples:
      employees = Person.find(:all, :from => "/companies/1/people.xml") # => GET /companies/1/people.xml
  manager   = Person.find("/companies/1/manager.xml")               # => GET /companies/1/manager.xml
  • Added support for using classes from within a single nested module [DHH]. Example:
      module Highrise
    class Note < ActiveResource::Base
      self.site = "http://37s.sunrise.i:3000"
    end

    class Comment < ActiveResource::Base
      self.site = "http://37s.sunrise.i:3000"
    end
  end

    assert_kind_of Highrise::Comment, Note.find(1).comments.first

  • Added load_attributes_from_response as a way of loading attributes from other responses than just create [DHH]
      class Highrise::Task < ActiveResource::Base
    def complete
      load_attributes_from_response(post(:complete))
    end
  end

    …will set "done_at" when complete is called.

  • Added support for calling custom methods 6979 [rwdaigle]
      Person.find(:managers)    # => GET /people/managers.xml
  Kase.find(1).post(:close) # => POST /kases/1/close.xml
  • Remove explicit prefix_options parameter for ActiveResource::Base#initialize. [Rick] ActiveResource splits the prefix_options from it automatically.
  • Allow ActiveResource::Base.delete with custom prefix. [Rick]
  • Add ActiveResource::Base#dup [Rick]
  • Fixed constant warning when fetching the same object multiple times [DHH]
  • Added that saves which get a body response (and not just a 201) will use that response to update themselves [DHH]
  • Disregard namespaces from the default element name, so Highrise::Person will just try to fetch from "/people", not "/highrise/people" [DHH]
  • Allow array and hash query parameters. 7756 [Greg Spurrier]
  • Loading a resource preserves its prefix_options. 7353 [Ryan Daigle]
  • Carry over the convenience of create from ActiveRecord. Closes 7340. [Ryan Daigle]
  • Increase ActiveResource::Base test coverage. Closes 7173, 7174 [Rich Collins]
  • Interpret 422 Unprocessable Entity as ResourceInvalid. 7097 [dkubb]
  • Mega documentation patches. 7025, 7069 [rwdaigle]
  • Base.exists?(id, options) and Base#exists? check whether the resource is found. 6970 [rwdaigle]
  • Query string support. [untext, Jeremy Kemper]
      # GET /forums/1/topics.xml?sort=created_at
  Topic.find(:all, :forum_id => 1, :sort => 'created_at')
  • Base#==, eql?, and hash methods. == returns true if its argument is identical to self or if it‘s an instance of the same class, is not new?, and has the same id. eql? is an alias for ==. hash delegates to id. [Jeremy Kemper]
  • Allow subclassed resources to share the site info [Rick, Jeremy Kemper]

d

    class BeastResource < ActiveResource::Base
      self.site = 'http://beast.caboo.se'
    end

    class Forum < BeastResource
      # taken from BeastResource
      # self.site = 'http://beast.caboo.se'
    end

    class Topic < BeastResource
      self.site += '/forums/:forum_id'
    end
  • Fix issues with ActiveResource collection handling. Closes 6291. [bmilekic]
  • Use attr_accessor_with_default to dry up attribute initialization. References 6538. [Stuart Halloway]
  • Add basic logging support for logging outgoing requests. [Jamis Buck]
  • Add Base.delete for deleting resources without having to instantiate them first. [Jamis Buck]
  • Make save behavior mimic AR::Base#save (true on success, false on failure). [Jamis Buck]
  • Add Basic HTTP Authentication to ActiveResource (closes 6305). [jonathan]
  • Extracted id_from_response as an entry point for customizing how a created resource gets its own ID. By default, it extracts from the Location response header.
  • Optimistic locking: raise ActiveResource::ResourceConflict on 409 Conflict response. [Jeremy Kemper]
      # Example controller action
  def update
    @person.save!
  rescue ActiveRecord::StaleObjectError
    render :xml => @person.reload.to_xml, :status => '409 Conflict'
  end
  • Basic validation support [Rick Olson]

    Parses the xml response of ActiveRecord::Errors#to_xml with a similar interface to ActiveRecord::Errors.

      render :xml => @person.errors.to_xml, :status => '400 Validation Error'
  • Deep hashes are converted into collections of resources. [Jeremy Kemper]
      Person.new :name => 'Bob',
             :address => { :id => 1, :city => 'Portland' },
             :contacts => [{ :id => 1 }, { :id => 2 }]

    Looks for Address and Contact resources and creates them if unavailable. So clients can fetch a complex resource in a single request if you e.g.

      render :xml => @person.to_xml(:include => [:address, :contacts])

    in your controller action.

  • Major updates [Rick Olson]
    • Add full support for find/create/update/destroy
    • Add support for specifying prefixes.
    • Allow overriding of element_name, collection_name, and primary key
    • Provide simpler HTTP mock interface for testing

      # rails routing code map.resources :posts do |post|

        post.resources :comments

      end

      # ActiveResources class Post < ActiveResource::Base

        self.site = "http://37s.sunrise.i:3000/"

      end

      class Comment < ActiveResource::Base

        self.site = "http://37s.sunrise.i:3000/posts/:post_id/"

      end

      @post = Post.find 5 @comments = Comment.find :all, :post_id => @post.id

      @comment = Comment.new({:body => ‘hello world’}, {:post_id => @post.id}) @comment.save

  • Base.site= accepts URIs. 200...400 are valid response codes. PUT and POST request bodies default to ’’. [Jeremy Kemper]
  • Initial checkin: object-oriented client for restful HTTP resources which follow the Rails convention. [DHH]


File: README

File
README
Path: | activesupport/README
Modified: | Sun Mar 02 11:08:48 -0700 2008

Active Support — Utility classes and standard library extensions from Rails

Active Support is a collection of various utility classes and standard library extensions that were found useful for Rails. All these additions have hence been collected in this bundle as way to gather all that sugar that makes Ruby sweeter.

Download

The latest version of Active Support can be found at

  • rubyforge.org/project/showfiles.php?group_id=182

Documentation can be found at

  • as.rubyonrails.com

Installation

The preferred method of installing Active Support is through its GEM file. You‘ll need to have RubyGems installed for that, though. If you have it, then use:

  % [sudo] gem install activesupport-1.0.0.gem

License

Active Support is released under the MIT license.

Support

The Active Support homepage is www.rubyonrails.com. You can find the Active Support RubyForge page at rubyforge.org/projects/activesupport. And as Jim from Rake says:

   Feel free to submit commits or feature requests.  If you send a patch,
   remember to update the corresponding unit tests.  If fact, I prefer
   new feature to be submitted in the form of new unit tests.

For other information, feel free to ask on the ruby-talk mailing list (which is mirrored to comp.lang.ruby) or contact david@loudthinking.com.


Class: ActiveSupport::BufferedLogger

Class
ActiveSupport::BufferedLogger
In: | activesupport/lib/active_support/buffered_logger.rb
Parent: | Object

Inspired by the buffered logger idea by Ezra

Methods
  • add
  • auto_flush
  • auto_flushing=
  • close
  • flush
  • new
  • silence
Included Modules
  • Severity
Classes and Modules
Module ActiveSupport::BufferedLogger::Severity
Constants
MAX_BUFFER_SIZE = 1000
Attributes
[R] | auto_flushing
[R] | buffer
[RW] | level
Public Class methods
new(log, level = DEBUG)

[ show source ]

    # File activesupport/lib/active_support/buffered_logger.rb, line 38
38:     def initialize(log, level = DEBUG)
39:       @level         = level
40:       @buffer        = []
41:       @auto_flushing = 1
42:
43:       if log.respond_to?(:write)
44:         @log = log
45:       elsif File.exist?(log)
46:         @log = open(log, (File::WRONLY | File::APPEND))
47:         @log.sync = true
48:       else
49:         @log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
50:         @log.sync = true
51:         @log.write("# Logfile created on %s" % [Time.now.to_s])
52:       end
53:     end
Public Instance methods
add(severity, message = nil, progname = nil, &block)

[ show source ]

    # File activesupport/lib/active_support/buffered_logger.rb, line 55
55:     def add(severity, message = nil, progname = nil, &block)
56:       return if @level > severity
57:       message = (message || (block && block.call) || progname).to_s
58:       # If a newline is necessary then create a new message ending with a newline.
59:       # Ensures that the original message is not mutated.
60:       message = "#{message}\n" unless message[-1] == ?\n
61:       @buffer << message
62:       auto_flush
63:       message
64:     end
auto_flushing=(period)

Set the auto-flush period. Set to true to flush after every log message, to an integer to flush every N messages, or to false, nil, or zero to never auto-flush. If you turn auto-flushing off, be sure to regularly flush the log yourself — it will eat up memory until you do.

[ show source ]

    # File activesupport/lib/active_support/buffered_logger.rb, line 83
83:     def auto_flushing=(period)
84:       @auto_flushing =
85:         case period
86:         when true;                1
87:         when false, nil, 0;       MAX_BUFFER_SIZE
88:         when Integer;             period
89:         else raise ArgumentError, "Unrecognized auto_flushing period: #{period.inspect}"
90:         end
91:     end
close()

[ show source ]

     # File activesupport/lib/active_support/buffered_logger.rb, line 97
 97:     def close
 98:       flush
 99:       @log.close if @log.respond_to?(:close)
100:       @log = nil
101:     end
flush()

[ show source ]

    # File activesupport/lib/active_support/buffered_logger.rb, line 93
93:     def flush
94:       @log.write(@buffer.slice!(0..-1).to_s) unless @buffer.empty?
95:     end
silence(temporary_level = ERROR) {|self| ...}

Silences the logger for the duration of the block.

[ show source ]

    # File activesupport/lib/active_support/buffered_logger.rb, line 21
21:     def silence(temporary_level = ERROR)
22:       if silencer
23:         begin
24:           old_logger_level, self.level = level, temporary_level
25:           yield self
26:         ensure
27:           self.level = old_logger_level
28:         end
29:       else
30:         yield self
31:       end
32:     end
Protected Instance methods
auto_flush()

[ show source ]

     # File activesupport/lib/active_support/buffered_logger.rb, line 104
104:       def auto_flush
105:         flush if @buffer.size >= @auto_flushing
106:       end


Module: ActiveSupport::BufferedLogger::Severity

Module
ActiveSupport::BufferedLogger::Severity
In: activesupport/lib/active_support/buffered_logger.rb
Constants
DEBUG | = | 0
INFO | = | 1
WARN | = | 2
ERROR | = | 3
FATAL | = | 4
UNKNOWN | = | 5


Module: ActiveSupport::CoreExtensions::Array::Access

Module
ActiveSupport::CoreExtensions::Array::Access
In: activesupport/lib/active_support/core_ext/array/access.rb

Makes it easier to access parts of an array.

Methods
  • from
  • to
Public Instance methods
from(position)

Returns the remaining of the array from the position.

Examples:

  %w( a b c d ).from(0)  # => %w( a b c d )
  %w( a b c d ).from(2)  # => %w( c d )
  %w( a b c d ).from(10) # => nil

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/access.rb, line 12
12:         def from(position)
13:           self[position..-1]
14:         end
to(position)

Returns the beginning of the array up to the position.

Examples:

  %w( a b c d ).to(0)  # => %w( a )
  %w( a b c d ).to(2)  # => %w( a b c )
  %w( a b c d ).to(10) # => %w( a b c d )

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/access.rb, line 22
22:         def to(position)
23:           self[0..position]
24:         end


Module: ActiveSupport::CoreExtensions::Array::Conversions

Module
ActiveSupport::CoreExtensions::Array::Conversions
In: activesupport/lib/active_support/core_ext/array/conversions.rb
Methods
  • to_formatted_s
  • to_param
  • to_query
  • to_sentence
  • to_xml
Public Instance methods
to_formatted_s(format = :default)

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/conversions.rb, line 48
48:         def to_formatted_s(format = :default)
49:           case format
50:             when :db
51:               if respond_to?(:empty?) && self.empty?
52:                 "null"
53:               else
54:                 collect { |element| element.id }.join(",")
55:               end
56:             else
57:               to_default_s
58:           end
59:         end
to_param()

Calls to_param on all its elements and joins the result with slashes. This is used by url_for in Action Pack.

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/conversions.rb, line 28
28:         def to_param
29:           map(&:to_param).join '/'
30:         end
to_query(key)

Converts an array into a string suitable for use as a URL query string, using the given key as the param name.

Example:

  ['Rails', 'coding'].to_query('hobbies') => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/conversions.rb, line 37
37:         def to_query(key)
38:           collect { |value| value.to_query("#{key}[]") } * '&'
39:         end
to_sentence(options = {})

Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:

  • :connector - The word used to join the last element in arrays with two or more elements (default: "and")
  • :skip_last_comma - Set to true to return "a, b and c" instead of "a, b, and c".

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/conversions.rb, line 10
10:         def to_sentence(options = {})
11:           options.assert_valid_keys(:connector, :skip_last_comma)
12:           options.reverse_merge! :connector => 'and', :skip_last_comma => false
13:           options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == ''
14:
15:           case length
16:             when 0
17:               ""
18:             when 1
19:               self[0].to_s
20:             when 2
21:               "#{self[0]} #{options[:connector]}#{self[1]}"
22:             else
23:               "#{self[0...-1].join(', ')}#{options[:skip_last_comma] ? '' : ','} #{options[:connector]}#{self[-1]}"
24:           end
25:         end
to_xml(options = {}) {|xml if block_given?| ...}

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/conversions.rb, line 61
61:         def to_xml(options = {})
62:           raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml }
63:
64:           options[:root]     ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records"
65:           options[:children] ||= options[:root].singularize
66:           options[:indent]   ||= 2
67:           options[:builder]  ||= Builder::XmlMarkup.new(:indent => options[:indent])
68:
69:           root     = options.delete(:root).to_s
70:           children = options.delete(:children)
71:
72:           if !options.has_key?(:dasherize) || options[:dasherize]
73:             root = root.dasherize
74:           end
75:
76:           options[:builder].instruct! unless options.delete(:skip_instruct)
77:
78:           opts = options.merge({ :root => children })
79:
80:           xml = options[:builder]
81:           if empty?
82:             xml.tag!(root, options[:skip_types] ? {} : {:type => "array"})
83:           else
84:             xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) {
85:               yield xml if block_given?
86:               each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) }
87:             }
88:           end
89:         end


Module: ActiveSupport::CoreExtensions::Array::ExtractOptions

Module
ActiveSupport::CoreExtensions::Array::ExtractOptions
In: activesupport/lib/active_support/core_ext/array/extract_options.rb
Methods
  • extract_options!
Public Instance methods
extract_options!()

Extract options from a set of arguments. Removes and returns the last element in the array if it‘s a hash, otherwise returns a blank hash.

  def options(*args)
    args.extract_options!
  end

  options(1, 2)           # => {}
  options(1, 2, :a => :b) # => {:a=>:b}

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/extract_options.rb, line 13
13:         def extract_options!
14:           last.is_a?(::Hash) ? pop : {}
15:         end


Module: ActiveSupport::CoreExtensions::Array::Grouping

Module
ActiveSupport::CoreExtensions::Array::Grouping
In: activesupport/lib/active_support/core_ext/array/grouping.rb
Methods
  • in_groups_of
  • split
Public Instance methods
in_groups_of(number, fill_with = nil, &block)

Iterate over an array in groups of a certain size, padding any remaining slots with specified value (nil by default) unless it is false.

E.g.

  %w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g}
  ["1", "2", "3"]
  ["4", "5", "6"]
  ["7", nil, nil]

  %w(1 2 3).in_groups_of(2, '&nbsp;') {|g| p g}
  ["1", "2"]
  ["3", "&nbsp;"]

  %w(1 2 3).in_groups_of(2, false) {|g| p g}
  ["1", "2"]
  ["3"]

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/grouping.rb, line 25
25:         def in_groups_of(number, fill_with = nil, &block)
26:           if fill_with == false
27:             collection = self
28:           else
29:             # size % number gives how many extra we have;
30:             # subtracting from number gives how many to add;
31:             # modulo number ensures we don't add group of just fill.
32:             padding = (number - size % number) % number
33:             collection = dup.concat([fill_with] * padding)
34:           end
35:
36:           if block_given?
37:             collection.each_slice(number, &block)
38:           else
39:             returning [] do |groups|
40:               collection.each_slice(number) { |group| groups << group }
41:             end
42:           end
43:         end
split(value = nil, &block)

Divide the array into one or more subarrays based on a delimiting value or the result of an optional block.

ex.

  [1, 2, 3, 4, 5].split(3)                # => [[1, 2], [4, 5]]
  (1..10).to_a.split { |i| i % 3 == 0 }   # => [[1, 2], [4, 5], [7, 8], [10]]

[ show source ]

    # File activesupport/lib/active_support/core_ext/array/grouping.rb, line 52
52:         def split(value = nil, &block)
53:           block ||= Proc.new { |e| e == value }
54:
55:           inject([[]]) do |results, element|
56:             if block.call(element)
57:               results << []
58:             else
59:               results.last << element
60:             end
61:
62:             results
63:           end
64:         end


Module: ActiveSupport::CoreExtensions::Array::RandomAccess

Module
ActiveSupport::CoreExtensions::Array::RandomAccess
In: activesupport/lib/active_support/core_ext/array/random_access.rb
Methods
  • rand
Public Instance methods
rand()

Return a random element from the array.

[ show source ]

   # File activesupport/lib/active_support/core_ext/array/random_access.rb, line 6
6:         def rand
7:           self[Kernel.rand(length)]
8:         end


Module: ActiveSupport::CoreExtensions::Date::Behavior

Module
ActiveSupport::CoreExtensions::Date::Behavior
In: activesupport/lib/active_support/core_ext/date/behavior.rb
Methods
  • acts_like_date?
Public Instance methods
acts_like_date?()

Enable more predictable duck-typing on Date-like classes. See Object#acts_like?.

[ show source ]

   # File activesupport/lib/active_support/core_ext/date/behavior.rb, line 7
7:         def acts_like_date?
8:           true
9:         end


Module: ActiveSupport::CoreExtensions::Date::Calculations

Module
ActiveSupport::CoreExtensions::Date::Calculations
In: activesupport/lib/active_support/core_ext/date/calculations.rb

Enables the use of time calculations within Time itself

Methods
  • advance
  • ago
  • at_beginning_of_day
  • at_beginning_of_month
  • at_beginning_of_quarter
  • at_beginning_of_week
  • at_beginning_of_year
  • at_end_of_month
  • at_midnight
  • beginning_of_day
  • beginning_of_month
  • beginning_of_quarter
  • beginning_of_week
  • beginning_of_year
  • change
  • end_of_day
  • end_of_month
  • in
  • last_month
  • last_year
  • midnight
  • monday
  • months_ago
  • months_since
  • next_month
  • next_week
  • next_year
  • since
  • tomorrow
  • years_ago
  • years_since
  • yesterday
Classes and Modules
Module ActiveSupport::CoreExtensions::Date::Calculations::ClassMethods
Public Instance methods
advance(options)

Provides precise Date calculations for years, months, and days. The options parameter takes a hash with any of these keys: :years, :months, :weeks, :days.

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 72
72:         def advance(options)
73:           d = self
74:           d = d >> options.delete(:years) * 12 if options[:years]
75:           d = d >> options.delete(:months)     if options[:months]
76:           d = d +  options.delete(:weeks) * 7  if options[:weeks]
77:           d = d +  options.delete(:days)       if options[:days]
78:           d
79:         end
ago(seconds)

Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) and then subtracts the specified number of seconds

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 30
30:         def ago(seconds)
31:           to_time.since(-seconds)
32:         end
at_beginning_of_day()

Alias for beginning_of_day

at_beginning_of_month()

Alias for beginning_of_month

at_beginning_of_quarter()

Alias for beginning_of_quarter

at_beginning_of_week()

Alias for beginning_of_week

at_beginning_of_year()

Alias for beginning_of_year

at_end_of_month()

Alias for end_of_month

at_midnight()

Alias for beginning_of_day

beginning_of_day()

Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)

This method is also aliased as midnight at_midnight at_beginning_of_day

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 42
42:         def beginning_of_day
43:           to_time
44:         end
beginning_of_month()

Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)

This method is also aliased as at_beginning_of_month

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 152
152:         def beginning_of_month
153:           self.acts_like?(:time) ? change(:day => 1,:hour => 0, :min => 0, :sec => 0) : change(:day => 1)
154:         end
beginning_of_quarter()

Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00)

This method is also aliased as at_beginning_of_quarter

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 165
165:         def beginning_of_quarter
166:           beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
167:         end
beginning_of_week()

Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00)

This method is also aliased as monday at_beginning_of_week

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 136
136:         def beginning_of_week
137:           days_to_monday = self.wday!=0 ? self.wday-1 : 6
138:           result = self - days_to_monday
139:           self.acts_like?(:time) ? result.midnight : result
140:         end
beginning_of_year()

Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00)

This method is also aliased as at_beginning_of_year

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 171
171:         def beginning_of_year
172:           self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0) : change(:month => 1, :day => 1)
173:         end
change(options)

Returns a new Date where one or more of the elements have been changed according to the options parameter.

Examples:

  Date.new(2007, 5, 12).change(:day => 1)                  # => Date.new(2007, 5, 1)
  Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 87
87:         def change(options)
88:           ::Date.new(
89:             options[:year]  || self.year,
90:             options[:month] || self.month,
91:             options[:day]   || self.day
92:           )
93:         end
end_of_day()

Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 50
50:         def end_of_day
51:           to_time.end_of_day
52:         end
end_of_month()

Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00)

This method is also aliased as at_end_of_month

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 158
158:         def end_of_month
159:           last_day = ::Time.days_in_month( self.month, self.year )
160:           self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day)
161:         end
in(seconds)

Alias for since

last_month()

Short-hand for months_ago(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 126
126:         def last_month
127:           months_ago(1)
128:         end
last_year()

Short-hand for years_ago(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 116
116:         def last_year
117:           years_ago(1)
118:         end
midnight()

Alias for beginning_of_day

monday()

Alias for beginning_of_week

months_ago(months)

Returns a new Date/DateTime representing the time a number of specified months ago

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 96
96:         def months_ago(months)
97:           advance(:months => -months)
98:         end
months_since(months)

Returns a new Date/DateTime representing the time a number of specified months in the future

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 101
101:         def months_since(months)
102:           advance(:months => months)
103:         end
next_month()

Short-hand for months_since(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 131
131:         def next_month
132:           months_since(1)
133:         end
next_week(day = :monday)

Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 145
145:         def next_week(day = :monday)
146:           days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
147:           result = (self + 7).beginning_of_week + days_into_week[day]
148:           self.acts_like?(:time) ? result.change(:hour => 0) : result
149:         end
next_year()

Short-hand for years_since(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 121
121:         def next_year
122:           years_since(1)
123:         end
since(seconds)

Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) and then adds the specified number of seconds

This method is also aliased as in

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 36
36:         def since(seconds)
37:           to_time.since(seconds)
38:         end
tomorrow()

Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 182
182:         def tomorrow
183:           self + 1
184:         end
years_ago(years)

Returns a new Date/DateTime representing the time a number of specified years ago

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 106
106:         def years_ago(years)
107:           advance(:years => -years)
108:         end
years_since(years)

Returns a new Date/DateTime representing the time a number of specified years in the future

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 111
111:         def years_since(years)
112:           advance(:years => years)
113:         end
yesterday()

Convenience method which returns a new Date/DateTime representing the time 1 day ago

[ show source ]

     # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 177
177:         def yesterday
178:           self - 1
179:         end


Module: ActiveSupport::CoreExtensions::Date::Calculations::ClassMethods

Module
ActiveSupport::CoreExtensions::Date::Calculations::ClassMethods
In: activesupport/lib/active_support/core_ext/date/calculations.rb
Methods
  • tomorrow
  • yesterday
Public Instance methods
tomorrow()

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 23
23:           def tomorrow
24:             ::Date.today.tomorrow
25:           end
yesterday()

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/calculations.rb, line 19
19:           def yesterday
20:             ::Date.today.yesterday
21:           end


Module: ActiveSupport::CoreExtensions::Date::Conversions

Module
ActiveSupport::CoreExtensions::Date::Conversions
In: activesupport/lib/active_support/core_ext/date/conversions.rb

Getting dates in different convenient string representations and other objects

Methods
  • readable_inspect
  • to_date
  • to_datetime
  • to_formatted_s
  • to_time
  • xmlschema
Constants
DATE_FORMATS = { :short => "%e %b", :long => "%B %e, %Y", :db => "%Y-%m-%d", :long_ordinal => lambda { |date| date.strftime("%B #{date.day.ordinalize}, %Y") }, # => "April 25th, 2007" :rfc822 => "%e %b %Y"
Public Instance methods
readable_inspect()

Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 57
57:         def readable_inspect
58:           strftime("%a, %d %b %Y")
59:         end
to_date()

A method to keep Time, Date and DateTime instances interchangeable on conversions. In this case, it simply returns self.

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 63
63:         def to_date
64:           self
65:         end
to_datetime()

Converts a Date instance to a DateTime, where the time is set to the beginning of the day and UTC offset is set to 0.

Example:

  date = Date.new(2007, 11, 10)  # => Sat, 10 Nov 2007

  date.to_datetime               # => Sat, 10 Nov 2007 00:00:00 0000

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 88
88:         def to_datetime
89:           ::DateTime.civil(year, month, day, 0, 0, 0, 0)
90:         end
to_formatted_s(format = :default)

Convert to a formatted string - see DATE_FORMATS for predefined formats. You can also add your own formats to the DATE_FORMATS constant and use them with this method.

This method is also aliased as to_s.

Examples:

  date = Date.new(2007, 11, 10)       # => Sat, 10 Nov 2007

  date.to_formatted_s(:db)            # => "2007-11-10"
  date.to_s(:db)                      # => "2007-11-10"

  date.to_formatted_s(:short)         # => "10 Nov"
  date.to_formatted_s(:long)          # => "November 10, 2007"
  date.to_formatted_s(:long_ordinal)  # => "November 10th, 2007"
  date.to_formatted_s(:rfc822)        # => "10 Nov 2007"

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 44
44:         def to_formatted_s(format = :default)
45:           if formatter = DATE_FORMATS[format]
46:             if formatter.respond_to?(:call)
47:               formatter.call(self).to_s
48:             else
49:               strftime(formatter)
50:             end
51:           else
52:             to_default_s
53:           end
54:         end
to_time(form = :local)

Converts a Date instance to a Time, where the time is set to the beginning of the day. The timezone can be either :local or :utc (default :local).

Examples:

  date = Date.new(2007, 11, 10)  # => Sat, 10 Nov 2007

  date.to_time                   # => Sat Nov 10 00:00:00 0800 2007
  date.to_time(:local)           # => Sat Nov 10 00:00:00 0800 2007

  date.to_time(:utc)             # => Sat Nov 10 00:00:00 UTC 2007

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 77
77:         def to_time(form = :local)
78:           ::Time.send("#{form}_time", year, month, day)
79:         end
xmlschema()

[ show source ]

    # File activesupport/lib/active_support/core_ext/date/conversions.rb, line 92
92:         def xmlschema
93:           to_time.xmlschema
94:         end


Module: ActiveSupport::CoreExtensions::DateTime::Calculations

Module
ActiveSupport::CoreExtensions::DateTime::Calculations
In: activesupport/lib/active_support/core_ext/date_time/calculations.rb

Enables the use of time calculations within DateTime itself

Methods
  • advance
  • ago
  • at_beginning_of_day
  • at_midnight
  • beginning_of_day
  • change
  • end_of_day
  • in
  • midnight
  • seconds_since_midnight
  • since
Classes and Modules
Module ActiveSupport::CoreExtensions::DateTime::Calculations::ClassMethods
Public Instance methods
advance(options)

Uses Date to provide precise Time calculations for years, months, and days. The options parameter takes a hash with any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 42
42:         def advance(options)
43:           d = to_date.advance(options)
44:           datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
45:           seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
46:           seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
47:         end
ago(seconds)

Returns a new DateTime representing the time a number of seconds ago Do not use this method in combination with x.months, use months_ago instead!

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 51
51:         def ago(seconds)
52:           self.since(-seconds)
53:         end
at_beginning_of_day()

Alias for beginning_of_day

at_midnight()

Alias for beginning_of_day

beginning_of_day()

Returns a new DateTime representing the start of the day (0:00)

This method is also aliased as midnight at_midnight at_beginning_of_day

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 63
63:         def beginning_of_day
64:           change(:hour => 0)
65:         end
change(options)

Returns a new DateTime where one or more of the elements have been changed according to the options parameter. The time options (hour, minute, sec) reset cascadingly, so if only the hour is passed, then minute and sec is set to 0. If the hour and minute is passed, then sec is set to 0.

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 27
27:         def change(options)
28:           ::DateTime.civil(
29:             options[:year]  || self.year,
30:             options[:month] || self.month,
31:             options[:day]   || self.day,
32:             options[:hour]  || self.hour,
33:             options[:min]   || (options[:hour] ? 0 : self.min),
34:             options[:sec]   || ((options[:hour] || options[:min]) ? 0 : self.sec),
35:             options[:offset]  || self.offset,
36:             options[:start]  || self.start
37:           )
38:         end
end_of_day()

Returns a new DateTime representing the end of the day (23:59:59)

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 71
71:         def end_of_day
72:           change(:hour => 23, :min => 59, :sec => 59)
73:         end
in(seconds)

Alias for since

midnight()

Alias for beginning_of_day

seconds_since_midnight()

Seconds since midnight: DateTime.now.seconds_since_midnight

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 20
20:         def seconds_since_midnight
21:           self.sec + (self.min * 60) + (self.hour * 3600)
22:         end
since(seconds)

Returns a new DateTime representing the time a number of seconds since the instance time Do not use this method in combination with x.months, use months_since instead!

This method is also aliased as in

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 57
57:         def since(seconds)
58:           self + Rational(seconds.round, 86400)
59:         end


Module: ActiveSupport::CoreExtensions::DateTime::Calculations::ClassMethods

Module
ActiveSupport::CoreExtensions::DateTime::Calculations::ClassMethods
In: activesupport/lib/active_support/core_ext/date_time/calculations.rb
Methods
  • local_offset
Public Instance methods
local_offset()

DateTimes aren‘t aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 14
14:           def local_offset
15:             ::Time.local(2007).utc_offset.to_r / 86400
16:           end


Module: ActiveSupport::CoreExtensions::DateTime::Conversions

Module
ActiveSupport::CoreExtensions::DateTime::Conversions
In: activesupport/lib/active_support/core_ext/date_time/conversions.rb

Getting datetimes in different convenient string representations and other objects

Methods
  • included
  • readable_inspect
  • to_date
  • to_datetime
  • to_formatted_s
  • to_time
  • xmlschema
Public Class methods
included(base)

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 6
 6:         def self.included(base)
 7:           base.class_eval do
 8:             alias_method :to_datetime_default_s, :to_s
 9:             alias_method :to_s, :to_formatted_s
10:             alias_method :default_inspect, :inspect
11:             alias_method :inspect, :readable_inspect
12:
13:             # Ruby 1.9 has DateTime#to_time which internally relies on Time. We define our own #to_time which allows
14:             # DateTimes outside the range of what can be created with Time.
15:             remove_method :to_time if base.instance_methods.include?(:to_time)
16:           end
17:         end
Public Instance methods
readable_inspect()

Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000"

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 47
47:         def readable_inspect
48:           to_s(:rfc822)
49:         end
to_date()

Converts self to a Ruby Date object; time portion is discarded

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 52
52:         def to_date
53:           ::Date.new(year, month, day)
54:         end
to_datetime()

To be able to keep Times, Dates and DateTimes interchangeable on conversions

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 63
63:         def to_datetime
64:           self
65:         end
to_formatted_s(format = :default)

Convert to a formatted string - see DATE_FORMATS for predefined formats. You can also add your own formats to the DATE_FORMATS constant and use them with this method.

This method is also aliased as to_s.

Examples:

  datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0)   # => Tue, 04 Dec 2007 00:00:00 +0000

  datetime.to_formatted_s(:db)            # => "2007-12-04 00:00:00"
  datetime.to_s(:db)                      # => "2007-12-04 00:00:00"
  datetime.to_s(:number)                  # => "20071204000000"
  datetime.to_formatted_s(:short)         # => "04 Dec 00:00"
  datetime.to_formatted_s(:long)          # => "December 04, 2007 00:00"
  datetime.to_formatted_s(:long_ordinal)  # => "December 4th, 2007 00:00"
  datetime.to_formatted_s(:rfc822)        # => "Tue, 04 Dec 2007 00:00:00 +0000"

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 34
34:         def to_formatted_s(format = :default)
35:           if formatter = ::Time::DATE_FORMATS[format]
36:             if formatter.respond_to?(:call)
37:               formatter.call(self).to_s
38:             else
39:               strftime(formatter)
40:             end
41:           else
42:             to_datetime_default_s
43:           end
44:         end
to_time()

Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class If self has an offset other than 0, self will just be returned unaltered, since there‘s no clean way to map it to a Time

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 58
58:         def to_time
59:           self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
60:         end
xmlschema()

Converts datetime to an appropriate format for use in XML

[ show source ]

    # File activesupport/lib/active_support/core_ext/date_time/conversions.rb, line 68
68:         def xmlschema
69:           strftime("%Y-%m-%dT%H:%M:%S%Z")
70:         end


Module: ActiveSupport::CoreExtensions::Float::Rounding

Module
ActiveSupport::CoreExtensions::Float::Rounding
In: activesupport/lib/active_support/core_ext/float/rounding.rb
Methods
  • round_with_precision
Public Instance methods
round_with_precision(precision = nil)

Rounds the float with the specified precision.

  x = 1.337
  x.round    # => 1
  x.round(1) # => 1.3
  x.round(2) # => 1.34

[ show source ]

    # File activesupport/lib/active_support/core_ext/float/rounding.rb, line 18
18:         def round_with_precision(precision = nil)
19:           precision.nil? ? round_without_precision : (self * (10 ** precision)).round / (10 ** precision).to_f
20:         end


Module: ActiveSupport::CoreExtensions::Hash::ClassMethods

Module
ActiveSupport::CoreExtensions::Hash::ClassMethods
In: activesupport/lib/active_support/core_ext/hash/conversions.rb
Methods
  • from_xml
Public Instance methods
from_xml(xml)

[ show source ]

     # File activesupport/lib/active_support/core_ext/hash/conversions.rb, line 153
153:           def from_xml(xml)
154:             # TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple
155:             typecast_xml_value(undasherize_keys(XmlSimple.xml_in_string(xml,
156:               'forcearray'   => false,
157:               'forcecontent' => true,
158:               'keeproot'     => true,
159:               'contentkey'   => '__content__')
160:             ))
161:           end


Module: ActiveSupport::CoreExtensions::Hash::Conversions

Module
ActiveSupport::CoreExtensions::Hash::Conversions
In: activesupport/lib/active_support/core_ext/hash/conversions.rb
Constants
XML_TYPE_NAMES | = | { "Symbol" => "symbol", "Fixnum" => "integer", "Bignum" => "integer", "BigDecimal" => "decimal", "Float" => "float", "Date" => "date", "DateTime" => "datetime", "Time" => "datetime", "TrueClass" => "boolean", "FalseClass" => "boolean"
XML_FORMATTING | = | { "symbol" => Proc.new { |symbol| symbol.to_s }, "date" => Proc.new { |date| date.to_s(:db) }, "datetime" => Proc.new { |time| time.xmlschema }, "binary" => Proc.new { |binary| Base64.encode64(binary) }, "yaml" => Proc.new { |yaml| yaml.to_yaml }
XML_PARSING | = | { "symbol" => Proc.new { |symbol| symbol.to_sym }, "date" => Proc.new { |date| ::Date.parse(date) }, "datetime" => Proc.new { |time| ::Time.parse(time).utc }, "integer" => Proc.new { |integer| integer.to_i }, "float" => Proc.new { |float| float.to_f }, "decimal" => Proc.new { |number| BigDecimal(number) }, "boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) }, "string" => Proc.new { |string| string.to_s }, "yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml }, "base64Binary" => Proc.new { |bin| Base64.decode64(bin) }, # FIXME: Get rid of eval and institute a proper decorator here "file" => Proc.new do |file, entity| f = StringIO.new(Base64.decode64(file))


Module: ActiveSupport::CoreExtensions::Hash::Diff

Module
ActiveSupport::CoreExtensions::Hash::Diff
In: activesupport/lib/active_support/core_ext/hash/diff.rb
Methods
  • diff
Public Instance methods
diff(h2)

Returns a hash that represents the difference between two hashes.

Examples:

  {1 => 2}.diff(1 => 2)         # => {}
  {1 => 2}.diff(1 => 3)         # => {1 => 2}
  {}.diff(1 => 2)               # => {1 => 2}
  {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/diff.rb, line 13
13:         def diff(h2)
14:           self.dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| self.has_key?(k) })
15:         end


Module: ActiveSupport::CoreExtensions::Hash::Except

Module
ActiveSupport::CoreExtensions::Hash::Except
In: activesupport/lib/active_support/core_ext/hash/except.rb

Return a hash that includes everything but the given keys. This is useful for limiting a set of parameters to everything but a few known toggles:

  @person.update_attributes(params[:person].except(:admin))
Methods
  • except
  • except!
Public Instance methods
except(*keys)

Returns a new hash without the given keys.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/except.rb, line 12
12:         def except(*keys)
13:           rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
14:           reject { |key,| rejected.include?(key) }
15:         end
except!(*keys)

Replaces the hash without only the given keys.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/except.rb, line 18
18:         def except!(*keys)
19:           replace(except(*keys))
20:         end


Module: ActiveSupport::CoreExtensions::Hash::Keys

Module
ActiveSupport::CoreExtensions::Hash::Keys
In: activesupport/lib/active_support/core_ext/hash/keys.rb
Methods
  • assert_valid_keys
  • stringify_keys
  • stringify_keys!
  • symbolize_keys
  • symbolize_keys!
  • to_options
  • to_options!
Public Instance methods
assert_valid_keys(*valid_keys)

Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch. Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbol as keys, this will fail. examples:

  { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
  { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): years, name"
  { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/keys.rb, line 47
47:         def assert_valid_keys(*valid_keys)
48:           unknown_keys = keys - [valid_keys].flatten
49:           raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
50:         end
stringify_keys()

Return a new hash with all keys converted to strings.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/keys.rb, line 6
 6:         def stringify_keys
 7:           inject({}) do |options, (key, value)|
 8:             options[key.to_s] = value
 9:             options
10:           end
11:         end
stringify_keys!()

Destructively convert all keys to strings.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/keys.rb, line 14
14:         def stringify_keys!
15:           keys.each do |key|
16:             unless key.class.to_s == "String" # weird hack to make the tests run when string_ext_test.rb is also running
17:               self[key.to_s] = self[key]
18:               delete(key)
19:             end
20:           end
21:           self
22:         end
symbolize_keys()

Return a new hash with all keys converted to symbols.

This method is also aliased as to_options

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/keys.rb, line 25
25:         def symbolize_keys
26:           inject({}) do |options, (key, value)|
27:             options[key.to_sym || key] = value
28:             options
29:           end
30:         end
symbolize_keys!()

Destructively convert all keys to symbols.

This method is also aliased as to_options!

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/keys.rb, line 33
33:         def symbolize_keys!
34:           self.replace(self.symbolize_keys)
35:         end
to_options()

Alias for symbolize_keys

to_options!()

Alias for symbolize_keys!


Module: ActiveSupport::CoreExtensions::Hash::ReverseMerge

Module
ActiveSupport::CoreExtensions::Hash::ReverseMerge
In: activesupport/lib/active_support/core_ext/hash/reverse_merge.rb

Allows for reverse merging where its the keys in the calling hash that wins over those in the other_hash. This is particularly useful for initializing an incoming option hash with default values:

  def setup(options = {})
    options.reverse_merge! :size => 25, :velocity => 10
  end

The default :size and :velocity is only set if the options passed in doesn‘t already have those keys set.

Methods
  • reverse_merge
  • reverse_merge!
  • reverse_update
Public Instance methods
reverse_merge(other_hash)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/reverse_merge.rb, line 13
13:         def reverse_merge(other_hash)
14:           other_hash.merge(self)
15:         end
reverse_merge!(other_hash)
This method is also aliased as reverse_update

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/reverse_merge.rb, line 17
17:         def reverse_merge!(other_hash)
18:           replace(reverse_merge(other_hash))
19:         end
reverse_update(other_hash)

Alias for reverse_merge!


Module: ActiveSupport::CoreExtensions::Hash::Slice

Module
ActiveSupport::CoreExtensions::Hash::Slice
In: activesupport/lib/active_support/core_ext/hash/slice.rb

Slice a hash to include only the given keys. This is useful for limiting an options hash to valid keys before passing to a method:

  def search(criteria = {})
    assert_valid_keys(:mass, :velocity, :time)
  end

  search(options.slice(:mass, :velocity, :time))
Methods
  • slice
  • slice!
Public Instance methods
slice(*keys)

Returns a new hash with only the given keys.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/slice.rb, line 16
16:         def slice(*keys)
17:           allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
18:           reject { |key,| !allowed.include?(key) }
19:         end
slice!(*keys)

Replaces the hash with only the given keys.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/slice.rb, line 22
22:         def slice!(*keys)
23:           replace(slice(*keys))
24:         end


Module: ActiveSupport::CoreExtensions::Integer::EvenOdd

Module
ActiveSupport::CoreExtensions::Integer::EvenOdd
In: activesupport/lib/active_support/core_ext/integer/even_odd.rb

For checking if a fixnum is even or odd.

  • 1.even? # => false
  • 1.odd? # => true
  • 2.even? # => true
  • 2.odd? # => false
Methods
  • even?
  • multiple_of?
  • odd?
Public Instance methods
even?()

[ show source ]

    # File activesupport/lib/active_support/core_ext/integer/even_odd.rb, line 14
14:         def even?
15:           multiple_of? 2
16:         end
multiple_of?(number)

[ show source ]

    # File activesupport/lib/active_support/core_ext/integer/even_odd.rb, line 10
10:         def multiple_of?(number)
11:           self % number == 0
12:         end
odd?()

[ show source ]

    # File activesupport/lib/active_support/core_ext/integer/even_odd.rb, line 18
18:         def odd?
19:           !even?
20:         end


Module: ActiveSupport::CoreExtensions::Integer::Inflections

Module
ActiveSupport::CoreExtensions::Integer::Inflections
In: activesupport/lib/active_support/core_ext/integer/inflections.rb
Methods
  • ordinalize
Public Instance methods
ordinalize()

Ordinalize turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th.

Examples

  1.ordinalize    # => "1st"
  2.ordinalize    # => "2nd"
  1002.ordinalize # => "1002nd"
  1003.ordinalize # => "1003rd"

[ show source ]

    # File activesupport/lib/active_support/core_ext/integer/inflections.rb, line 15
15:         def ordinalize
16:           Inflector.ordinalize(self)
17:         end


Module: ActiveSupport::CoreExtensions::Numeric::Bytes

Module
ActiveSupport::CoreExtensions::Numeric::Bytes
In: activesupport/lib/active_support/core_ext/numeric/bytes.rb

Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes

Methods
  • byte
  • bytes
  • exabyte
  • exabytes
  • gigabyte
  • gigabytes
  • kilobyte
  • kilobytes
  • megabyte
  • megabytes
  • petabyte
  • petabytes
  • terabyte
  • terabytes
Public Instance methods
byte()

Alias for bytes

bytes()
This method is also aliased as byte

[ show source ]

   # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 6
6:         def bytes
7:           self
8:         end
exabyte()

Alias for exabytes

exabytes()
This method is also aliased as exabyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 36
36:         def exabytes
37:           self * 1024.petabytes
38:         end
gigabyte()

Alias for gigabytes

gigabytes()
This method is also aliased as gigabyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 21
21:         def gigabytes
22:           self * 1024.megabytes
23:         end
kilobyte()

Alias for kilobytes

kilobytes()
This method is also aliased as kilobyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 11
11:         def kilobytes
12:           self * 1024
13:         end
megabyte()

Alias for megabytes

megabytes()
This method is also aliased as megabyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 16
16:         def megabytes
17:           self * 1024.kilobytes
18:         end
petabyte()

Alias for petabytes

petabytes()
This method is also aliased as petabyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 31
31:         def petabytes
32:           self * 1024.terabytes
33:         end
terabyte()

Alias for terabytes

terabytes()
This method is also aliased as terabyte

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/bytes.rb, line 26
26:         def terabytes
27:           self * 1024.gigabytes
28:         end


Module: ActiveSupport::CoreExtensions::Numeric::Time

Module
ActiveSupport::CoreExtensions::Numeric::Time
In: activesupport/lib/active_support/core_ext/numeric/time.rb

Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.

These methods use Time#advance for precise date calculations when using from_now, ago, etc. as well as adding or subtracting their results from a Time object. For example:

  # equivalent to Time.now.advance(:months => 1)
  1.month.from_now

  # equivalent to Time.now.advance(:years => 2)
  2.years.from_now

  # equivalent to Time.now.advance(:months => 4, :years => 5)
  (4.months + 5.years).from_now

While these methods provide precise calculation when used as in the examples above, care should be taken to note that this is not true if the result of `months’, `years’, etc is converted before use:

  # equivalent to 30.days.to_i.from_now
  1.month.to_i.from_now

  # equivalent to 365.25.days.to_f.from_now
  1.year.to_f.from_now

In such cases, Ruby‘s core Date and Time should be used for precision date and time arithmetic

Methods
  • ago
  • day
  • days
  • fortnight
  • fortnights
  • from_now
  • hour
  • hours
  • minute
  • minutes
  • month
  • months
  • second
  • seconds
  • since
  • until
  • week
  • weeks
  • year
  • years
Public Instance methods
ago(time = ::Time.now)

Reads best without arguments: 10.minutes.ago

This method is also aliased as until

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 74
74:         def ago(time = ::Time.now)
75:           time - self
76:         end
day()

Alias for days

days()
This method is also aliased as day

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 48
48:         def days
49:           ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
50:         end
fortnight()

Alias for fortnights

fortnights()
This method is also aliased as fortnight

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 58
58:         def fortnights
59:           ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
60:         end
from_now(time = ::Time.now)

Alias for since

hour()

Alias for hours

hours()
This method is also aliased as hour

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 43
43:         def hours
44:           ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
45:         end
minute()

Alias for minutes

minutes()
This method is also aliased as minute

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 38
38:         def minutes
39:           ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
40:         end
month()

Alias for months

months()
This method is also aliased as month

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 63
63:         def months
64:           ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
65:         end
second()

Alias for seconds

seconds()
This method is also aliased as second

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 33
33:         def seconds
34:           ActiveSupport::Duration.new(self, [[:seconds, self]])
35:         end
since(time = ::Time.now)

Reads best with argument: 10.minutes.since(time)

This method is also aliased as from_now

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 82
82:         def since(time = ::Time.now)
83:           time + self
84:         end
until(time = ::Time.now)

Alias for ago

week()

Alias for weeks

weeks()
This method is also aliased as week

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 53
53:         def weeks
54:           ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
55:         end
year()

Alias for years

years()
This method is also aliased as year

[ show source ]

    # File activesupport/lib/active_support/core_ext/numeric/time.rb, line 68
68:         def years
69:           ActiveSupport::Duration.new(self * 365.25.days, [[:years, self]])
70:         end


Module: ActiveSupport::CoreExtensions::Pathname::CleanWithin

Module
ActiveSupport::CoreExtensions::Pathname::CleanWithin
In: activesupport/lib/active_support/core_ext/pathname/clean_within.rb
Methods
  • clean_within
Public Instance methods
clean_within(string)

Clean the paths contained in the provided string.

[ show source ]

    # File activesupport/lib/active_support/core_ext/pathname/clean_within.rb, line 6
 6:         def clean_within(string)
 7:           string.gsub(%r{[\w. ]+(/[\w. ]+)+(\.rb)?(\b|$)}) do |path|
 8:             new(path).cleanpath
 9:           end
10:         end


Module: ActiveSupport::CoreExtensions::Range::BlocklessStep

Module
ActiveSupport::CoreExtensions::Range::BlocklessStep
In: activesupport/lib/active_support/core_ext/range/blockless_step.rb

Return an array when step is called without a block.

Methods
  • step_with_blockless
Public Instance methods
step_with_blockless(value, &block)

[ show source ]

    # File activesupport/lib/active_support/core_ext/range/blockless_step.rb, line 10
10:         def step_with_blockless(value, &block)
11:           if block_given?
12:             step_without_blockless(value, &block)
13:           else
14:             returning [] do |array|
15:               step_without_blockless(value) { |step| array << step }
16:             end
17:           end
18:         end


Module: ActiveSupport::CoreExtensions::Range::Conversions

Module
ActiveSupport::CoreExtensions::Range::Conversions
In: activesupport/lib/active_support/core_ext/range/conversions.rb

Getting ranges in different convenient string representations and other objects

Methods
  • to_formatted_s
Constants
RANGE_FORMATS = { :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
Public Instance methods
to_formatted_s(format = :default)

[ show source ]

    # File activesupport/lib/active_support/core_ext/range/conversions.rb, line 17
17:         def to_formatted_s(format = :default)
18:           RANGE_FORMATS[format] ? RANGE_FORMATS[format].call(first, last) : to_default_s
19:         end


Module: ActiveSupport::CoreExtensions::Range::IncludeRange

Module
ActiveSupport::CoreExtensions::Range::IncludeRange
In: activesupport/lib/active_support/core_ext/range/include_range.rb

Check if a Range includes another Range.

Methods
  • include_with_range?
Public Instance methods
include_with_range?(value)

[ show source ]

    # File activesupport/lib/active_support/core_ext/range/include_range.rb, line 10
10:         def include_with_range?(value)
11:           if value.is_a?(::Range)
12:             operator = exclude_end? ? :< : :<=
13:             end_value = value.exclude_end? ? last.succ : last
14:             include?(value.first) && (value.last <=> end_value).send(operator, 0)
15:           else
16:             include_without_range?(value)
17:           end
18:         end


Module: ActiveSupport::CoreExtensions::Range::Overlaps

Module
ActiveSupport::CoreExtensions::Range::Overlaps
In: activesupport/lib/active_support/core_ext/range/overlaps.rb

Check if Ranges overlap.

Methods
  • overlaps?
Public Instance methods
overlaps?(other)

[ show source ]

   # File activesupport/lib/active_support/core_ext/range/overlaps.rb, line 6
6:         def overlaps?(other)
7:           include?(other.first) || other.include?(first)
8:         end


Module: ActiveSupport::CoreExtensions::String::Access

Module
ActiveSupport::CoreExtensions::String::Access
In: activesupport/lib/active_support/core_ext/string/access.rb

Makes it easier to access parts of a string, such as specific characters and substrings.

Methods
  • at
  • first
  • from
  • last
  • to
Public Instance methods
at(position)

Returns the character at the position treating the string as an array (where 0 is the first character).

Examples:

  "hello".at(0)  # => "h"
  "hello".at(4)  # => "o"
  "hello".at(10) # => nil

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/access.rb, line 12
12:         def at(position)
13:           chars[position, 1].to_s
14:         end
first(limit = 1)

Returns the first character of the string or the first limit characters.

Examples:

  "hello".first     # => "h"
  "hello".first(2)  # => "he"
  "hello".first(10) # => "hello"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/access.rb, line 42
42:         def first(limit = 1)
43:           chars[0..(limit - 1)].to_s
44:         end
from(position)

Returns the remaining of the string from the position treating the string as an array (where 0 is the first character).

Examples:

  "hello".from(0)  # => "hello"
  "hello".from(2)  # => "llo"
  "hello".from(10) # => nil

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/access.rb, line 22
22:         def from(position)
23:           chars[position..-1].to_s
24:         end
last(limit = 1)

Returns the last character of the string or the last limit characters.

Examples:

  "hello".last     # => "o"
  "hello".last(2)  # => "lo"
  "hello".last(10) # => "hello"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/access.rb, line 52
52:         def last(limit = 1)
53:           (chars[(-limit)..-1] || self).to_s
54:         end
to(position)

Returns the beginning of the string up to the position treating the string as an array (where 0 is the first character).

Examples:

  "hello".to(0)  # => "h"
  "hello".to(2)  # => "hel"
  "hello".to(10) # => "hello"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/access.rb, line 32
32:         def to(position)
33:           chars[0..position].to_s
34:         end


Module: ActiveSupport::CoreExtensions::String::Conversions

Module
ActiveSupport::CoreExtensions::String::Conversions
In: activesupport/lib/active_support/core_ext/string/conversions.rb

Converting strings to other objects

Methods
  • ord
  • to_date
  • to_datetime
  • to_time
Public Instance methods
ord()

‘a’.ord == ‘a’[0] for Ruby 1.9 forward compatibility.

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/conversions.rb, line 9
 9:         def ord
10:           self[0]
11:         end
to_date()

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/conversions.rb, line 18
18:         def to_date
19:           ::Date.new(*ParseDate.parsedate(self)[0..2])
20:         end
to_datetime()

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/conversions.rb, line 22
22:         def to_datetime
23:           ::DateTime.civil(*ParseDate.parsedate(self)[0..5].map {|arg| arg || 0} << 0)
24:         end
to_time(form = :utc)

Form can be either :utc (default) or :local.

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/conversions.rb, line 14
14:         def to_time(form = :utc)
15:           ::Time.send("#{form}_time", *ParseDate.parsedate(self)[0..5].map {|arg| arg || 0})
16:         end


Module: ActiveSupport::CoreExtensions::String::Inflections

Module
ActiveSupport::CoreExtensions::String::Inflections
In: activesupport/lib/active_support/core_ext/string/inflections.rb

String inflections define new methods on the String class to transform names for different purposes. For instance, you can figure out the name of a database from the name of a class.

  "ScaleScore".tableize => "scale_scores"
Methods
  • camelcase
  • camelize
  • classify
  • constantize
  • dasherize
  • demodulize
  • foreign_key
  • humanize
  • pluralize
  • singularize
  • tableize
  • titlecase
  • titleize
  • underscore
Public Instance methods
camelcase(first_letter = :upper)

Alias for camelize

camelize(first_letter = :upper)

By default, camelize converts strings to UpperCamelCase. If the argument to camelize is set to ":lower" then camelize produces lowerCamelCase.

camelize will also convert ’/’ to ’::’ which is useful for converting paths to namespaces

Examples

  "active_record".camelize #=> "ActiveRecord"
  "active_record".camelize(:lower) #=> "activeRecord"
  "active_record/errors".camelize #=> "ActiveRecord::Errors"
  "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
This method is also aliased as camelcase

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 46
46:         def camelize(first_letter = :upper)
47:           case first_letter
48:             when :upper then Inflector.camelize(self, true)
49:             when :lower then Inflector.camelize(self, false)
50:           end
51:         end
classify()

Create a class name from a table name like Rails does for table names to models. Note that this returns a string and not a Class. (To convert to an actual class follow classify with constantize.)

Examples

  "egg_and_hams".classify #=> "EggAndHam"
  "post".classify #=> "Post"

[ show source ]

     # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 114
114:         def classify
115:           Inflector.classify(self)
116:         end
constantize()

Constantize tries to find a declared constant with the name specified in the string. It raises a NameError when the name is not in CamelCase or is not initialized.

Examples

  "Module".constantize #=> Module
  "Class".constantize #=> Class

[ show source ]

     # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 147
147:         def constantize
148:           Inflector.constantize(self)
149:         end
dasherize()

Replaces underscores with dashes in the string.

Example

  "puni_puni" #=> "puni-puni"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 83
83:         def dasherize
84:           Inflector.dasherize(self)
85:         end
demodulize()

Removes the module part from the expression in the string

Examples

  "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
  "Inflections".demodulize #=> "Inflections"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 92
92:         def demodulize
93:           Inflector.demodulize(self)
94:         end
foreign_key(separate_class_name_and_id_with_underscore = true)

Creates a foreign key name from a class name. separate_class_name_and_id_with_underscore sets whether the method should put ‘_’ between the name and ‘id’.

Examples

  "Message".foreign_key #=> "message_id"
  "Message".foreign_key(false) #=> "messageid"
  "Admin::Post".foreign_key #=> "post_id"

[ show source ]

     # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 136
136:         def foreign_key(separate_class_name_and_id_with_underscore = true)
137:           Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
138:         end
humanize()

Capitalizes the first word and turns underscores into spaces and strips _id. Like titleize, this is meant for creating pretty output.

Examples

  "employee_salary" #=> "Employee salary"
  "author_id" #=> "Author"

[ show source ]

     # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 124
124:         def humanize
125:           Inflector.humanize(self)
126:         end
pluralize()

Returns the plural form of the word in the string.

Examples

  "post".pluralize #=> "posts"
  "octopus".pluralize #=> "octopi"
  "sheep".pluralize #=> "sheep"
  "words".pluralize #=> "words"
  "the blue mailman".pluralize #=> "the blue mailmen"
  "CamelOctopus".pluralize #=> "CamelOctopi"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 19
19:         def pluralize
20:           Inflector.pluralize(self)
21:         end
singularize()

The reverse of pluralize, returns the singular form of a word in a string.

Examples

  "posts".singularize #=> "post"
  "octopi".singularize #=> "octopus"
  "sheep".singluarize #=> "sheep"
  "word".singluarize #=> "word"
  "the blue mailmen".singularize #=> "the blue mailman"
  "CamelOctopi".singularize #=> "CamelOctopus"

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 32
32:         def singularize
33:           Inflector.singularize(self)
34:         end
tableize()

Create the name of a table like Rails does for models to table names. This method uses the pluralize method on the last word in the string.

Examples

  "RawScaledScorer".tableize #=> "raw_scaled_scorers"
  "egg_and_ham".tableize #=> "egg_and_hams"
  "fancyCategory".tableize #=> "fancy_categories"

[ show source ]

     # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 103
103:         def tableize
104:           Inflector.tableize(self)
105:         end
titlecase()

Alias for titleize

titleize()

Capitalizes all the words and replaces some characters in the string to create a nicer looking title. Titleize is meant for creating pretty output. It is not used in the Rails internals.

titleize is also aliased as as titlecase

Examples

  "man from the boondocks".titleize #=> "Man From The Boondocks"
  "x-men: the last stand".titleize #=> "X Men: The Last Stand"
This method is also aliased as titlecase

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 63
63:         def titleize
64:           Inflector.titleize(self)
65:         end
underscore()

The reverse of camelize. Makes an underscored form from the expression in the string.

Changes ’::’ to ’/’ to convert namespaces to paths.

Examples

  "ActiveRecord".underscore #=> "active_record"
  "ActiveRecord::Errors".underscore #=> active_record/errors

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/inflections.rb, line 75
75:         def underscore
76:           Inflector.underscore(self)
77:         end


Module: ActiveSupport::CoreExtensions::String::Iterators

Module
ActiveSupport::CoreExtensions::String::Iterators
In: activesupport/lib/active_support/core_ext/string/iterators.rb

Custom string iterators

Methods
  • each_char
Public Instance methods
each_char() {|scanner.scan(char || break)| ...}

Yields a single-character string for each character in the string. When $KCODE = ‘UTF8’, multi-byte characters are yielded appropriately.

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/iterators.rb, line 10
10:         def each_char
11:           scanner, char = StringScanner.new(self), /./mu
12:           loop { yield(scanner.scan(char) || break) }
13:         end


Module: ActiveSupport::CoreExtensions::String::StartsEndsWith

Module
ActiveSupport::CoreExtensions::String::StartsEndsWith
In: activesupport/lib/active_support/core_ext/string/starts_ends_with.rb

Additional string tests.

Methods
  • ends_with?
  • included
  • starts_with?
Public Class methods
included(base)

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/starts_ends_with.rb, line 6
 6:         def self.included(base)
 7:           base.class_eval do
 8:             alias_method :start_with?, :starts_with?
 9:             alias_method :end_with?, :ends_with?
10:           end
11:         end
Public Instance methods
ends_with?(suffix)

Does the string end with the specified suffix?

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/starts_ends_with.rb, line 20
20:         def ends_with?(suffix)
21:           suffix = suffix.to_s
22:           self[-suffix.length, suffix.length] == suffix
23:         end
starts_with?(prefix)

Does the string start with the specified prefix?

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/starts_ends_with.rb, line 14
14:         def starts_with?(prefix)
15:           prefix = prefix.to_s
16:           self[0, prefix.length] == prefix
17:         end


Module: ActiveSupport::CoreExtensions::String::Unicode

Module
ActiveSupport::CoreExtensions::String::Unicode
In: activesupport/lib/active_support/core_ext/string/unicode.rb

Define methods for handling unicode data.

Methods
  • chars
  • is_utf8?
Public Instance methods
chars()

chars is a Unicode safe proxy for string methods. It creates and returns an instance of the ActiveSupport::Multibyte::Chars class which encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy class. Undefined methods are forwarded to String, so all of the string overrides can also be called through the chars proxy.

  name = 'Claus Müller'
  name.reverse #=> "rell??M sualC"
  name.length #=> 13

  name.chars.reverse.to_s #=> "rellüM sualC"
  name.chars.length #=> 12

All the methods on the chars proxy which normally return a string will return a Chars object. This allows method chaining on the result of any of these methods.

  name.chars.reverse.length #=> 12

The Char object tries to be as interchangeable with String objects as possible: sorting and comparing between String and Char work like expected. The bang! methods change the internal string representation in the Chars object. Interoperability problems can be resolved easily with a to_s call.

For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars and ActiveSupport::Multibyte::Handlers::UTF8Handler

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/unicode.rb, line 30
30:         def chars
31:           ActiveSupport::Multibyte::Chars.new(self)
32:         end
is_utf8?()

Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have them), returns false otherwise.

[ show source ]

    # File activesupport/lib/active_support/core_ext/string/unicode.rb, line 36
36:         def is_utf8?
37:           ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(self)
38:         end


Module: ActiveSupport::CoreExtensions::Time::Behavior

Module
ActiveSupport::CoreExtensions::Time::Behavior
In: activesupport/lib/active_support/core_ext/time/behavior.rb
Methods
  • acts_like_time?
Public Instance methods
acts_like_time?()

Enable more predictable duck-typing on Time-like classes. See Object#acts_like?.

[ show source ]

   # File activesupport/lib/active_support/core_ext/time/behavior.rb, line 7
7:         def acts_like_time?
8:           true
9:         end


Module: ActiveSupport::CoreExtensions::Time::Calculations

Module
ActiveSupport::CoreExtensions::Time::Calculations
In: activesupport/lib/active_support/core_ext/time/calculations.rb

Enables the use of time calculations within Time itself

Methods
  • advance
  • ago
  • at_beginning_of_day
  • at_beginning_of_month
  • at_beginning_of_quarter
  • at_beginning_of_week
  • at_beginning_of_year
  • at_end_of_month
  • at_midnight
  • beginning_of_day
  • beginning_of_month
  • beginning_of_quarter
  • beginning_of_week
  • beginning_of_year
  • change
  • end_of_day
  • end_of_month
  • in
  • last_month
  • last_year
  • midnight
  • monday
  • months_ago
  • months_since
  • next_month
  • next_week
  • next_year
  • seconds_since_midnight
  • since
  • tomorrow
  • years_ago
  • years_since
  • yesterday
Classes and Modules
Module ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods
Public Instance methods
advance(options)

Uses Date to provide precise Time calculations for years, months, and days. The options parameter takes a hash with any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 76
76:         def advance(options)
77:           d = to_date.advance(options)
78:           time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
79:           seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
80:           seconds_to_advance == 0 ? time_advanced_by_date : time_advanced_by_date.since(seconds_to_advance)
81:         end
ago(seconds)

Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension Do not use this method in combination with x.months, use months_ago instead!

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 85
85:         def ago(seconds)
86:           self.since(-seconds)
87:         end
at_beginning_of_day()

Alias for beginning_of_day

at_beginning_of_month()

Alias for beginning_of_month

at_beginning_of_quarter()

Alias for beginning_of_quarter

at_beginning_of_week()

Alias for beginning_of_week

at_beginning_of_year()

Alias for beginning_of_year

at_end_of_month()

Alias for end_of_month

at_midnight()

Alias for beginning_of_day

beginning_of_day()

Returns a new Time representing the start of the day (0:00)

This method is also aliased as midnight at_midnight at_beginning_of_day

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 157
157:         def beginning_of_day
158:           (self - self.seconds_since_midnight).change(:usec => 0)
159:         end
beginning_of_month()

Returns a new Time representing the start of the month (1st of the month, 0:00)

This method is also aliased as at_beginning_of_month

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 170
170:         def beginning_of_month
171:           #self - ((self.mday-1).days + self.seconds_since_midnight)
172:           change(:day => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
173:         end
beginning_of_quarter()

Returns a new Time representing the start of the quarter (1st of january, april, july, october, 0:00)

This method is also aliased as at_beginning_of_quarter

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 185
185:         def beginning_of_quarter
186:           beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
187:         end
beginning_of_week()

Returns a new Time representing the "start" of this week (Monday, 0:00)

This method is also aliased as monday at_beginning_of_week

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 143
143:         def beginning_of_week
144:           days_to_monday = self.wday!=0 ? self.wday-1 : 6
145:           (self - days_to_monday.days).midnight
146:         end
beginning_of_year()

Returns a new Time representing the start of the year (1st of january, 0:00)

This method is also aliased as at_beginning_of_year

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 191
191:         def beginning_of_year
192:           change(:month => 1,:day => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
193:         end
change(options)

Returns a new Time where one or more of the elements have been changed according to the options parameter. The time options (hour, minute, sec, usec) reset cascadingly, so if only the hour is passed, then minute, sec, and usec is set to 0. If the hour and minute is passed, then sec and usec is set to 0.

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 61
61:         def change(options)
62:           ::Time.send(
63:             self.utc? ? :utc_time : :local_time,
64:             options[:year]  || self.year,
65:             options[:month] || self.month,
66:             options[:day]   || self.day,
67:             options[:hour]  || self.hour,
68:             options[:min]   || (options[:hour] ? 0 : self.min),
69:             options[:sec]   || ((options[:hour] || options[:min]) ? 0 : self.sec),
70:             options[:usec]  || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
71:           )
72:         end
end_of_day()

Returns a new Time representing the end of the day (23:59:59)

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 165
165:         def end_of_day
166:           change(:hour => 23, :min => 59, :sec => 59)
167:         end
end_of_month()

Returns a new Time representing the end of the month (last day of the month, 0:00)

This method is also aliased as at_end_of_month

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 177
177:         def end_of_month
178:           #self - ((self.mday-1).days + self.seconds_since_midnight)
179:           last_day = ::Time.days_in_month( self.month, self.year )
180:           change(:day => last_day, :hour => 23, :min => 59, :sec => 59, :usec => 0)
181:         end
in(seconds)

Alias for since

last_month()

Short-hand for months_ago(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 133
133:         def last_month
134:           months_ago(1)
135:         end
last_year()

Short-hand for years_ago(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 122
122:         def last_year
123:           years_ago(1)
124:         end
midnight()

Alias for beginning_of_day

monday()

Alias for beginning_of_week

months_ago(months)

Returns a new Time representing the time a number of specified months ago

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 102
102:         def months_ago(months)
103:           advance(:months => -months)
104:         end
months_since(months)

Returns a new Time representing the time a number of specified months in the future

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 107
107:         def months_since(months)
108:           advance(:months => months)
109:         end
next_month()

Short-hand for months_since(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 138
138:         def next_month
139:           months_since(1)
140:         end
next_week(day = :monday)

Returns a new Time representing the start of the given day in next week (default is Monday).

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 151
151:         def next_week(day = :monday)
152:           days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
153:           since(1.week).beginning_of_week.since(days_into_week[day].day).change(:hour => 0)
154:         end
next_year()

Short-hand for years_since(1)

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 127
127:         def next_year
128:           years_since(1)
129:         end
seconds_since_midnight()

Seconds since midnight: Time.now.seconds_since_midnight

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 54
54:         def seconds_since_midnight
55:           self.to_i - self.change(:hour => 0).to_i + (self.usec/1.0e+6)
56:         end
since(seconds)

Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around the Numeric extension. Do not use this method in combination with x.months, use months_since instead!

This method is also aliased as in

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 91
91:         def since(seconds)
92:           initial_dst = self.dst? ? 1 : 0
93:           f = seconds.since(self)
94:           final_dst   = f.dst? ? 1 : 0
95:           (seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
96:         rescue
97:           self.to_datetime.since(seconds)
98:         end
tomorrow()

Convenience method which returns a new Time representing the time 1 day since the instance time

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 202
202:         def tomorrow
203:           self.since(1.day)
204:         end
years_ago(years)

Returns a new Time representing the time a number of specified years ago

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 112
112:         def years_ago(years)
113:           advance(:years => -years)
114:         end
years_since(years)

Returns a new Time representing the time a number of specified years in the future

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 117
117:         def years_since(years)
118:           advance(:years => years)
119:         end
yesterday()

Convenience method which returns a new Time representing the time 1 day ago

[ show source ]

     # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 197
197:         def yesterday
198:           self.ago(1.day)
199:         end


Module: ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods

Module
ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods
In: activesupport/lib/active_support/core_ext/time/calculations.rb
Methods
  • days_in_month
  • local_time
  • time_with_datetime_fallback
  • utc_time
Public Instance methods
days_in_month(month, year=nil)

Return the number of days in the given month. If a year is given, February will return the correct number of days for leap years. Otherwise, this method will always report February as having 28 days.

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 22
22:           def days_in_month(month, year=nil)
23:             if month == 2
24:               !year.nil? && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ?  29 : 28
25:             elsif month <= 7
26:               month % 2 == 0 ? 30 : 31
27:             else
28:               month % 2 == 0 ? 31 : 30
29:             end
30:           end
local_time(*args)

wraps class method time_with_datetime_fallback with utc_or_local == :local

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 48
48:           def local_time(*args)
49:             time_with_datetime_fallback(:local, *args)
50:           end
time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)

Returns a new Time if requested year can be accommodated by Ruby‘s Time class (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture); otherwise returns a DateTime

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 35
35:           def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
36:             ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
37:           rescue
38:             offset = utc_or_local.to_sym == :local ? ::DateTime.local_offset : 0
39:             ::DateTime.civil(year, month, day, hour, min, sec, offset)
40:           end
utc_time(*args)

wraps class method time_with_datetime_fallback with utc_or_local == :utc

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/calculations.rb, line 43
43:           def utc_time(*args)
44:             time_with_datetime_fallback(:utc, *args)
45:           end


Module: ActiveSupport::CoreExtensions::Time::Conversions

Module
ActiveSupport::CoreExtensions::Time::Conversions
In: activesupport/lib/active_support/core_ext/time/conversions.rb

Getting times in different convenient string representations and other objects

Methods
  • included
  • to_date
  • to_datetime
  • to_formatted_s
  • to_time
Constants
DATE_FORMATS = { :db => "%Y-%m-%d %H:%M:%S", :time => "%H:%M", :short => "%d %b %H:%M", :long => "%B %d, %Y %H:%M", :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") }, :rfc822 => "%a, %d %b %Y %H:%M:%S %z"
Public Class methods
included(base)

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/conversions.rb, line 15
15:         def self.included(base)
16:           base.class_eval do
17:             alias_method :to_default_s, :to_s
18:             alias_method :to_s, :to_formatted_s
19:           end
20:         end
Public Instance methods
to_date()

Convert a Time object to a Date, dropping hour, minute, and second precision.

Examples

  my_time = Time.now
  # => Mon Nov 12 22:59:51 -0500 2007

  my_time.to_date
  #=> Mon, 12 Nov 2007

  your_time = Time.parse("1/13/2009 1:13:03 P.M.")
  # => Tue Jan 13 13:13:03 -0500 2009

  your_time.to_date
  # => Tue, 13 Jan 2009

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/conversions.rb, line 64
64:         def to_date
65:           ::Date.new(year, month, day)
66:         end
to_datetime()

Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.

Examples

  my_time = Time.now
  # => Mon Nov 12 23:04:21 -0500 2007

  my_time.to_datetime
  # => Mon, 12 Nov 2007 23:04:21 -0500

  your_time = Time.parse("1/13/2009 1:13:03 P.M.")
  # => Tue Jan 13 13:13:03 -0500 2009

  your_time.to_datetime
  # => Tue, 13 Jan 2009 13:13:03 -0500

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/conversions.rb, line 88
88:         def to_datetime
89:           ::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400))
90:         end
to_formatted_s(format = :default)

Convert to a formatted string - see DATE_FORMATS for predefined formats. You can also add your own formats to the DATE_FORMATS constant and use them with this method.

This method is also aliased as to_s.

Examples:

  time = Time.now                     # => Thu Jan 18 06:10:17 CST 2007

  time.to_formatted_s(:time)          # => "06:10:17"
  time.to_s(:time)                    # => "06:10:17"

  time.to_formatted_s(:db)            # => "2007-01-18 06:10:17"
  time.to_formatted_s(:short)         # => "18 Jan 06:10"
  time.to_formatted_s(:long)          # => "January 18, 2007 06:10"
  time.to_formatted_s(:long_ordinal)  # => "January 18th, 2007 06:10"
  time.to_formatted_s(:rfc822)        # => "Thu, 18 Jan 2007 06:10:17 -0600"

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/conversions.rb, line 38
38:         def to_formatted_s(format = :default)
39:           if formatter = DATE_FORMATS[format]
40:             if formatter.respond_to?(:call)
41:               formatter.call(self).to_s
42:             else
43:               strftime(formatter)
44:             end
45:           else
46:             to_default_s
47:           end
48:         end
to_time()

A method to keep Time, Date and DateTime instances interchangeable on conversions. In this case, it simply returns self.

[ show source ]

    # File activesupport/lib/active_support/core_ext/time/conversions.rb, line 70
70:         def to_time
71:           self
72:         end


Class: ActiveSupport::Duration

Class
ActiveSupport::Duration
In: | activesupport/lib/active_support/duration.rb
Parent: | BasicObject

Provides accurate date and time measurements using Date#advance and Time#advance, respectively. It mainly supports the methods on Numeric, such as in this example:

  1.month.ago       # equivalent to Time.now.advance(:months => -1)
Methods
  • +
  • -
  • ==
  • ago
  • from_now
  • since
  • until
Attributes
[RW] | parts
[RW] | value
Public Instance methods
+(other)

Adds another Duration or a Numeric to this Duration. Numeric values are treated as seconds.

[ show source ]

    # File activesupport/lib/active_support/duration.rb, line 16
16:     def +(other)
17:       if Duration === other
18:         Duration.new(value + other.value, @parts + other.parts)
19:       else
20:         Duration.new(value + other, @parts + [[:seconds, other]])
21:       end
22:     end
-(other)

Subtracts another Duration or a Numeric from this Duration. Numeric values are treated as seconds.

[ show source ]

    # File activesupport/lib/active_support/duration.rb, line 26
26:     def -(other)
27:       self + (-other)
28:     end
==(other)

Returns true if other is also a Duration instance with the same value, or if other == value.

[ show source ]

    # File activesupport/lib/active_support/duration.rb, line 40
40:     def ==(other)
41:       if Duration === other
42:         other.value == value
43:       else
44:         other == value
45:       end
46:     end
ago(time = ::Time.now)

Calculates a new Time or Date that is as far in the past as this Duration represents.

This method is also aliased as until

[ show source ]

    # File activesupport/lib/active_support/duration.rb, line 61
61:     def ago(time = ::Time.now)
62:       sum(-1, time)
63:     end
from_now(time = ::Time.now)

Alias for since

since(time = ::Time.now)

Calculates a new Time or Date that is as far in the future as this Duration represents.

This method is also aliased as from_now

[ show source ]

    # File activesupport/lib/active_support/duration.rb, line 54
54:     def since(time = ::Time.now)
55:       sum(1, time)
56:     end
until(time = ::Time.now)

Alias for ago


Module: ActiveSupport::JSON

Module
ActiveSupport::JSON
In: activesupport/lib/active_support/json/decoding.rb activesupport/lib/active_support/json/encoders/string.rb activesupport/lib/active_support/json/encoding.rb activesupport/lib/active_support/json/variable.rb activesupport/lib/active_support/json.rb
Methods
  • decode
  • encode
Classes and Modules
Module ActiveSupport::JSON::Encoding
Class ActiveSupport::JSON::CircularReferenceError
Class ActiveSupport::JSON::ParseError
Class ActiveSupport::JSON::Variable
Constants
DATE_REGEX | = | /^\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?$/
 | matches YAML-formatted dates
Public Class methods
decode(json)

Converts a JSON string into a Ruby object.

[ show source ]

    # File activesupport/lib/active_support/json/decoding.rb, line 11
11:       def decode(json)
12:         YAML.load(convert_json_to_yaml(json))
13:       rescue ArgumentError => e
14:         raise ParseError, "Invalid JSON string"
15:       end
encode(value, options = {})

Converts a Ruby object into a JSON string.

[ show source ]

    # File activesupport/lib/active_support/json/encoding.rb, line 20
20:       def encode(value, options = {})
21:         raise_on_circular_reference(value) do
22:           value.send(:to_json, options)
23:         end
24:       end


Class: ActiveSupport::JSON::CircularReferenceError

Class
ActiveSupport::JSON::CircularReferenceError
In: | activesupport/lib/active_support/json/encoding.rb
Parent: | StandardError


Module: ActiveSupport::JSON::Encoding

Module
ActiveSupport::JSON::Encoding
In: activesupport/lib/active_support/json/encoders/string.rb
Constants
ESCAPED_CHARS = { "\010" => '\b', "\f" => '\f', "\n" => '\n', "\r" => '\r', "\t" => '\t', '"' => '\"', '\\' => '\\\\', '>' => '\u003E', '<' => '\u003C', '&' => '\u0026'


Class: ActiveSupport::JSON::ParseError

Class
ActiveSupport::JSON::ParseError
In: | activesupport/lib/active_support/json/decoding.rb
Parent: | StandardError


Class: ActiveSupport::JSON::Variable

Class
ActiveSupport::JSON::Variable
In: | activesupport/lib/active_support/json/variable.rb
Parent: | String

A string that returns itself as its JSON-encoded form.

Methods
  • to_json
Public Instance methods
to_json(options=nil)

[ show source ]

   # File activesupport/lib/active_support/json/variable.rb, line 5
5:       def to_json(options=nil)
6:         self
7:       end


Class: ActiveSupport::Multibyte::Chars

Class
ActiveSupport::Multibyte::Chars
In: | activesupport/lib/active_support/multibyte/chars.rb
Parent: | Object

Chars enables you to work transparently with multibyte encodings in the Ruby String class without having extensive knowledge about the encoding. A Chars object accepts a string upon initialization and proxies String methods in an encoding safe manner. All the normal String methods are also implemented on the proxy.

String methods are proxied through the Chars object, and can be accessed through the chars method. Methods which would normally return a String object now return a Chars object so methods can be chained.

  "The Perfect String  ".chars.downcase.strip.normalize #=> "the perfect string"

Chars objects are perfectly interchangeable with String objects as long as no explicit class checks are made. If certain methods do explicitly check the class, call to_s before you pass chars objects to them.

  bad.explicit_checking_method "T".chars.downcase.to_s

The actual operations on the string are delegated to handlers. Theoretically handlers can be implemented for any encoding, but the default handler handles UTF-8. This handler is set during initialization, if you want to use you own handler, you can set it on the Chars class. Look at the UTF8Handler source for an example how to implement your own handler. If you your own handler to work on anything but UTF-8 you probably also want to override Chars#handler.

  ActiveSupport::Multibyte::Chars.handler = MyHandler

Note that a few methods are defined on Chars instead of the handler because they are defined on Object or Kernel and method_missing can‘t catch them.

Methods
  • <=>
  • =~
  • gsub
  • handler
  • handler=
  • method_missing
  • new
  • respond_to?
  • split
  • to_str
Included Modules
  • Comparable
Attributes
[R] string
Public Class methods
handler=(klass)

Set the handler class for the Char objects.

[ show source ]

     # File activesupport/lib/active_support/multibyte/chars.rb, line 104
104:     def self.handler=(klass)
105:       @@handler = klass
106:     end
new(str)

Create a new Chars instance.

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 51
51:     def initialize(str)
52:       @string = str.respond_to?(:string) ? str.string : str
53:     end
Public Instance methods
<=>(other)

Returns -1, 0 or +1 depending on whether the Chars object is to be sorted before, equal or after the object on the right side of the operation. It accepts any object that implements to_s. See String.<=> for more details.

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 58
58:     def <=>(other); @string <=> other.to_s; end
=~(other)

Like String.=~ only it returns the character offset (in codepoints) instead of the byte offset.

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 70
70:     def =~(other)
71:       handler.translate_offset(@string, @string =~ other)
72:     end
gsub(*a, &b)

Gsub works exactly the same as gsub on a normal string.

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 67
67:     def gsub(*a, &b); @string.gsub(*a, &b).chars; end
handler()

Returns the proper handler for the contained string depending on $KCODE and the encoding of the string. This method is used internally to always redirect messages to the proper classes depending on the context.

[ show source ]

     # File activesupport/lib/active_support/multibyte/chars.rb, line 110
110:     def handler
111:       if utf8_pragma?
112:         @@handler
113:       else
114:         ActiveSupport::Multibyte::Handlers::PassthruHandler
115:       end
116:     end
method_missing(m, *a, &b)

Try to forward all undefined methods to the handler, when a method is not defined on the handler, send it to the contained string. Method_missing is also responsible for making the bang! methods destructive.

[ show source ]

     # File activesupport/lib/active_support/multibyte/chars.rb, line 76
 76:     def method_missing(m, *a, &b)
 77:       begin
 78:         # Simulate methods with a ! at the end because we can't touch the enclosed string from the handlers.
 79:         if m.to_s =~ /^(.*)\!$/ && handler.respond_to?($1)
 80:           result = handler.send($1, @string, *a, &b)
 81:           if result == @string
 82:             result = nil
 83:           else
 84:             @string.replace result
 85:           end
 86:         elsif handler.respond_to?(m)
 87:           result = handler.send(m, @string, *a, &b)
 88:         else
 89:           result = @string.send(m, *a, &b)
 90:         end
 91:       rescue Handlers::EncodingError
 92:         @string.replace handler.tidy_bytes(@string)
 93:         retry
 94:       end
 95:
 96:       if result.kind_of?(String)
 97:         result.chars
 98:       else
 99:         result
100:       end
101:     end
respond_to?(method)

Make duck-typing with String possible

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 45
45:     def respond_to?(method)
46:       super || @string.respond_to?(method) || handler.respond_to?(method) ||
47:         (method.to_s =~ /(.*)!/ && handler.respond_to?($1)) || false
48:     end
split(*args)

Works just like String#split, with the exception that the items in the resulting list are Chars instances instead of String. This makes chaining methods easier.

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 62
62:     def split(*args)
63:       @string.split(*args).map { |i| i.chars }
64:     end
to_str()

The magic method to make String and Chars comparable

[ show source ]

    # File activesupport/lib/active_support/multibyte/chars.rb, line 38
38:     def to_str
39:       # Using any other ways of overriding the String itself will lead you all the way from infinite loops to
40:       # core dumps. Don't go there.
41:       @string
42:     end


Class: ActiveSupport::Multibyte::Handlers::UTF8Handler

Class
ActiveSupport::Multibyte::Handlers::UTF8Handler
In: | activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
Parent: | Object

UTF8Handler implements Unicode aware operations for strings, these operations will be used by the Chars proxy when $KCODE is set to ‘UTF8’.

Methods
  • []=
  • capitalize
  • center
  • compose
  • compose_codepoints
  • consumes?
  • decompose
  • decompose_codepoints
  • downcase
  • g_length
  • g_pack
  • g_unpack
  • in_char_class?
  • index
  • insert
  • justify
  • ljust
  • lstrip
  • normalize
  • padding
  • reorder_characters
  • reverse
  • rjust
  • rstrip
  • size
  • slice
  • strip
  • tidy_bytes
  • to_case
  • translate_offset
  • u_unpack
  • upcase
Constants
HANGUL_SBASE | = | 0xAC00
 | Hangul character boundaries and properties
HANGUL_LBASE | = | 0x1100
HANGUL_VBASE | = | 0x1161
HANGUL_TBASE | = | 0x11A7
HANGUL_LCOUNT | = | 19
HANGUL_VCOUNT | = | 21
HANGUL_TCOUNT | = | 28
HANGUL_NCOUNT | = | HANGUL_VCOUNT * HANGUL_TCOUNT
HANGUL_SCOUNT | = | 11172
HANGUL_SLAST | = | HANGUL_SBASE + HANGUL_SCOUNT
HANGUL_JAMO_FIRST | = | 0x1100
HANGUL_JAMO_LAST | = | 0x11FF
UNICODE_WHITESPACE | = | [ (0x0009..0x000D).to_a, # White_Space # Cc [5] <control-0009>..<control-000D> 0x0020, # White_Space # Zs SPACE 0x0085, # White_Space # Cc <control-0085> 0x00A0, # White_Space # Zs NO-BREAK SPACE 0x1680, # White_Space # Zs OGHAM SPACE MARK 0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE 0x2028, # White_Space # Zl LINE SEPARATOR 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE ].flatten.freeze
 | All the unicode whitespace
UNICODE_LEADERS_AND_TRAILERS | = | UNICODE_WHITESPACE + [65279]
 | BOM (byte order mark) can also be seen as whitespace, it‘s a non-rendering character used to distinguish between little and big endian. This is not an issue in utf-8, so it must be ignored.
UTF8_PAT | = | /\A(?: [\x00-\x7f] | [\xc2-\xdf] [\x80-\xbf] | \xe0 [\xa0-\xbf] [\x80-\xbf] | [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] | \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] | [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] | \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf] )*\z/xn
 | Borrowed from the Kconv library by Shinji KONO - (also as seen on the W3C site)
UNICODE_TRAILERS_PAT | = | /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/
UNICODE_LEADERS_PAT | = | /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/
UCD | = | UnicodeDatabase.new
 | UniCode Database
Public Class methods
[]=(str, *args)

Works just like the indexed replace method on string, except instead of byte offsets you specify character offsets.

Example:

  s = "Müller"
  s.chars[2] = "e" # Replace character with offset 2
  s
  #=> "Müeler"

  s = "Müller"
  s.chars[1, 2] = "ö" # Replace 2 characters at character offset 1
  s
  #=> "Möler"

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 158
158:       def []=(str, *args)
159:         replace_by = args.pop
160:         # Indexed replace with regular expressions already works
161:         return str[*args] = replace_by if args.first.is_a?(Regexp)
162:         result = u_unpack(str)
163:         if args[0].is_a?(Fixnum)
164:           raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
165:           min = args[0]
166:           max = args[1].nil? ? min : (min + args[1] - 1)
167:           range = Range.new(min, max)
168:           replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
169:         elsif args.first.is_a?(Range)
170:           raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
171:           range = args[0]
172:         else
173:           needle = args[0].to_s
174:           min = index(str, needle)
175:           max = min + length(needle) - 1
176:           range = Range.new(min, max)
177:         end
178:         result[range] = u_unpack(replace_by)
179:         str.replace(result.pack('U*'))
180:       end
capitalize(str)

Returns a copy of str with the first character converted to uppercase and the remainder to lowercase

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 276
276:       def capitalize(str)
277:         upcase(slice(str, 0..0)) + downcase(slice(str, 1..-1) || '')
278:       end
center(str, integer, padstr=' ')

Works just like String#center, only integer specifies characters instead of bytes.

Example:

  "¾ cup".chars.center(8).to_s
  #=> " ¾ cup  "

  "¾ cup".chars.center(8, " ").to_s # Use non-breaking whitespace
  #=> " ¾ cup  "

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 217
217:       def center(str, integer, padstr=' ')
218:         justify(str, integer, :center, padstr)
219:       end
compose(str)

Perform composition on the characters in the string

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 312
312:       def compose(str)
313:         compose_codepoints u_unpack(str).pack('U*')
314:       end
consumes?(str)

Checks if the string is valid UTF8.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 342
342:       def consumes?(str)
343:         # Unpack is a little bit faster than regular expressions
344:         begin
345:           str.unpack('U*')
346:           true
347:         rescue ArgumentError
348:           false
349:         end
350:       end
decompose(str)

Perform decomposition on the characters in the string

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 307
307:       def decompose(str)
308:         decompose_codepoints(:canonical, u_unpack(str)).pack('U*')
309:       end
downcase(str)

Convert characters in the string to lowercase

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 273
273:       def downcase(str); to_case :lowercase_mapping, str; end
g_length(str)

Returns the number of grapheme clusters in the string. This method is very likely to be moved or renamed in future versions.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 354
354:       def g_length(str)
355:         g_unpack(str).length
356:       end
index(str, *args)

Returns the position of the passed argument in the string, counting in codepoints

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 139
139:       def index(str, *args)
140:         bidx = str.index(*args)
141:         bidx ? (u_unpack(str.slice(0...bidx)).size) : nil
142:       end
insert(str, offset, fragment)

Inserts the passed string at specified codepoint offsets

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 129
129:       def insert(str, offset, fragment)
130:         str.replace(
131:           u_unpack(str).insert(
132:             offset,
133:             u_unpack(fragment)
134:           ).flatten.pack('U*')
135:         )
136:       end
ljust(str, integer, padstr=' ')

Works just like String#ljust, only integer specifies characters instead of bytes.

Example:

  "¾ cup".chars.rjust(8).to_s
  #=> "¾ cup   "

  "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
  #=> "¾ cup   "

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 204
204:       def ljust(str, integer, padstr=' ')
205:         justify(str, integer, :left, padstr)
206:       end
lstrip(str)

Does Unicode-aware lstrip

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 227
227:       def lstrip(str)
228:         str.gsub(UNICODE_LEADERS_PAT, '')
229:       end
normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM)

Returns the KC normalization of the string by default. NFKC is considered the best normalization form for passing strings to databases and validations.

  • str - The string to perform normalization on.
  • form - The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 289
289:       def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM)
290:         # See http://www.unicode.org/reports/tr15, Table 1
291:         codepoints = u_unpack(str)
292:         case form
293:           when :d
294:             reorder_characters(decompose_codepoints(:canonical, codepoints))
295:           when :c
296:             compose_codepoints reorder_characters(decompose_codepoints(:canonical, codepoints))
297:           when :kd
298:             reorder_characters(decompose_codepoints(:compatability, codepoints))
299:           when :kc
300:             compose_codepoints reorder_characters(decompose_codepoints(:compatability, codepoints))
301:           else
302:             raise ArgumentError, "#{form} is not a valid normalization variant", caller
303:         end.pack('U*')
304:       end
reverse(str)

Reverses codepoints in the string.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 243
243:       def reverse(str)
244:         u_unpack(str).reverse.pack('U*')
245:       end
rjust(str, integer, padstr=' ')

Works just like String#rjust, only integer specifies characters instead of bytes.

Example:

  "¾ cup".chars.rjust(8).to_s
  #=> "   ¾ cup"

  "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
  #=> "   ¾ cup"

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 191
191:       def rjust(str, integer, padstr=' ')
192:         justify(str, integer, :right, padstr)
193:       end
rstrip(str)

Does Unicode-aware rstrip

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 222
222:       def rstrip(str)
223:         str.gsub(UNICODE_TRAILERS_PAT, '')
224:       end
size(str)

Returns the number of codepoints in the string

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 237
237:       def size(str)
238:         u_unpack(str).size
239:       end
slice(str, *args)

Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that character.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 249
249:       def slice(str, *args)
250:         if args.size > 2
251:           raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
252:         elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp)))
253:           raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native
254:         elsif (args.size == 2 && !args[1].is_a?(Numeric))
255:           raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native
256:         elsif args[0].kind_of? Range
257:           cps = u_unpack(str).slice(*args)
258:           cps.nil? ? nil : cps.pack('U*')
259:         elsif args[0].kind_of? Regexp
260:           str.slice(*args)
261:         elsif args.size == 1 && args[0].kind_of?(Numeric)
262:           u_unpack(str)[args[0]]
263:         else
264:           u_unpack(str).slice(*args).pack('U*')
265:         end
266:       end
strip(str)

Removed leading and trailing whitespace

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 232
232:       def strip(str)
233:         str.gsub(UNICODE_LEADERS_PAT, '').gsub(UNICODE_TRAILERS_PAT, '')
234:       end
tidy_bytes(str)

Replaces all the non-utf-8 bytes by their iso-8859-1 or cp1252 equivalent resulting in a valid utf-8 string

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 359
359:       def tidy_bytes(str)
360:         str.split(//u).map do |c|
361:           if !UTF8_PAT.match(c)
362:             n = c.unpack('C')[0]
363:             n < 128 ? n.chr :
364:             n < 160 ? [UCD.cp1252[n] || n].pack('U') :
365:             n < 192 ? "\xC2" + n.chr : "\xC3" + (n-64).chr
366:           else
367:             c
368:           end
369:         end.join
370:       end
translate_offset(str, byte_offset)

Used to translate an offset from bytes to characters, for instance one received from a regular expression match

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 321
321:       def translate_offset(str, byte_offset)
322:         return nil if byte_offset.nil?
323:         return 0 if str == ''
324:         chunk = str[0..byte_offset]
325:         begin
326:           begin
327:             chunk.unpack('U*').length - 1
328:           rescue ArgumentError => e
329:             chunk = str[0..(byte_offset+=1)]
330:             # Stop retrying at the end of the string
331:             raise e unless byte_offset < chunk.length
332:             # We damaged a character, retry
333:             retry
334:           end
335:         # Catch the ArgumentError so we can throw our own
336:         rescue ArgumentError
337:           raise EncodingError.new('malformed UTF-8 character')
338:         end
339:       end
upcase(str)

Convert characters in the string to uppercase

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 270
270:       def upcase(str); to_case :uppercase_mapping, str; end
Protected Class methods
compose_codepoints(codepoints)

Compose decomposed characters to the composed form

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 503
503:       def compose_codepoints(codepoints)
504:         pos = 0
505:         eoa = codepoints.length - 1
506:         starter_pos = 0
507:         starter_char = codepoints[0]
508:         previous_combining_class = -1
509:         while pos < eoa
510:           pos += 1
511:           lindex = starter_char - HANGUL_LBASE
512:           # -- Hangul
513:           if 0 <= lindex and lindex < HANGUL_LCOUNT
514:             vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1
515:             if 0 <= vindex and vindex < HANGUL_VCOUNT
516:               tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1
517:               if 0 <= tindex and tindex < HANGUL_TCOUNT
518:                 j = starter_pos + 2
519:                 eoa -= 2
520:               else
521:                 tindex = 0
522:                 j = starter_pos + 1
523:                 eoa -= 1
524:               end
525:               codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE
526:             end
527:             starter_pos += 1
528:             starter_char = codepoints[starter_pos]
529:           # -- Other characters
530:           else
531:             current_char = codepoints[pos]
532:             current = UCD[current_char]
533:             if current.combining_class > previous_combining_class
534:               if ref = UCD.composition_map[starter_char]
535:                 composition = ref[current_char]
536:               else
537:                 composition = nil
538:               end
539:               unless composition.nil?
540:                 codepoints[starter_pos] = composition
541:                 starter_char = composition
542:                 codepoints.delete_at pos
543:                 eoa -= 1
544:                 pos -= 1
545:                 previous_combining_class = -1
546:               else
547:                 previous_combining_class = current.combining_class
548:               end
549:             else
550:               previous_combining_class = current.combining_class
551:             end
552:             if current.combining_class == 0
553:               starter_pos = pos
554:               starter_char = codepoints[pos]
555:             end
556:           end
557:         end
558:         codepoints
559:       end
decompose_codepoints(type, codepoints)

Decompose composed characters to the decomposed form

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 482
482:       def decompose_codepoints(type, codepoints)
483:         codepoints.inject([]) do |decomposed, cp|
484:           # if it's a hangul syllable starter character
485:           if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
486:             sindex = cp - HANGUL_SBASE
487:             ncp = [] # new codepoints
488:             ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
489:             ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
490:             tindex = sindex % HANGUL_TCOUNT
491:             ncp << (HANGUL_TBASE + tindex) unless tindex == 0
492:             decomposed.concat ncp
493:           # if the codepoint is decomposable in with the current decomposition type
494:           elsif (ncp = UCD[cp].decomp_mapping) and (!UCD[cp].decomp_type || type == :compatability)
495:             decomposed.concat decompose_codepoints(type, ncp.dup)
496:           else
497:             decomposed << cp
498:           end
499:         end
500:       end
g_pack(unpacked)

Reverse operation of g_unpack

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 421
421:       def g_pack(unpacked)
422:         unpacked.flatten
423:       end
g_unpack(str)

Unpack the string at grapheme boundaries instead of codepoint boundaries

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 390
390:       def g_unpack(str)
391:         codepoints = u_unpack(str)
392:         unpacked = []
393:         pos = 0
394:         marker = 0
395:         eoc = codepoints.length
396:         while(pos < eoc)
397:           pos += 1
398:           previous = codepoints[pos-1]
399:           current = codepoints[pos]
400:           if (
401:               # CR X LF
402:               one = ( previous == UCD.boundary[:cr] and current == UCD.boundary[:lf] ) or
403:               # L X (L|V|LV|LVT)
404:               two = ( UCD.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
405:               # (LV|V) X (V|T)
406:               three = ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
407:               # (LVT|T) X (T)
408:               four = ( in_char_class?(previous, [:lvt,:t]) and UCD.boundary[:t] === current ) or
409:               # X Extend
410:               five = (UCD.boundary[:extend] === current)
411:             )
412:           else
413:             unpacked << codepoints[marker..pos-1]
414:             marker = pos
415:           end
416:         end
417:         unpacked
418:       end
in_char_class?(codepoint, classes)

Detect whether the codepoint is in a certain character class. Primarily used by the grapheme cluster support.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 376
376:       def in_char_class?(codepoint, classes)
377:         classes.detect { |c| UCD.boundary[c] === codepoint } ? true : false
378:       end
justify(str, integer, way, padstr=' ')

Justifies a string in a certain way. Valid values for way are :right, :left and :center. Is primarily used as a helper method by rjust, ljust and center.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 427
427:       def justify(str, integer, way, padstr=' ')
428:         raise ArgumentError, "zero width padding" if padstr.length == 0
429:         padsize = integer - size(str)
430:         padsize = padsize > 0 ? padsize : 0
431:         case way
432:         when :right
433:           str.dup.insert(0, padding(padsize, padstr))
434:         when :left
435:           str.dup.insert(-1, padding(padsize, padstr))
436:         when :center
437:           lpad = padding((padsize / 2.0).floor, padstr)
438:           rpad = padding((padsize / 2.0).ceil, padstr)
439:           str.dup.insert(0, lpad).insert(-1, rpad)
440:         end
441:       end
padding(padsize, padstr=' ')

Generates a padding string of a certain size.

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 444
444:       def padding(padsize, padstr=' ')
445:         if padsize != 0
446:           slice(padstr * ((padsize / size(padstr)) + 1), 0, padsize)
447:         else
448:           ''
449:         end
450:       end
reorder_characters(codepoints)

Re-order codepoints so the string becomes canonical

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 466
466:       def reorder_characters(codepoints)
467:         length = codepoints.length- 1
468:         pos = 0
469:         while pos < length do
470:           cp1, cp2 = UCD[codepoints[pos]], UCD[codepoints[pos+1]]
471:           if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0)
472:             codepoints[pos..pos+1] = cp2.code, cp1.code
473:             pos += (pos > 0 ? -1 : 1)
474:           else
475:             pos += 1
476:           end
477:         end
478:         codepoints
479:       end
to_case(way, str)

Convert characters to a different case

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 453
453:       def to_case(way, str)
454:         u_unpack(str).map do |codepoint|
455:           cp = UCD[codepoint]
456:           unless cp.nil?
457:             ncp = cp.send(way)
458:             ncp > 0 ? ncp : codepoint
459:           else
460:             codepoint
461:           end
462:         end.pack('U*')
463:       end
u_unpack(str)

Unpack the string at codepoints boundaries

[ show source ]

     # File activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb, line 381
381:       def u_unpack(str)
382:         begin
383:           str.unpack 'U*'
384:         rescue ArgumentError
385:           raise EncodingError.new('malformed UTF-8 character')
386:         end
387:       end


Class: ActiveSupport::TestCase

Class
ActiveSupport::TestCase
In: | activesupport/lib/active_support/test_case.rb
Parent: | Test::Unit::TestCase
Included Modules
  • ActiveSupport::Testing::Default


Module: ActiveSupport::Testing

Module
ActiveSupport::Testing
In: activesupport/lib/active_support/testing/default.rb
Classes and Modules
Module ActiveSupport::Testing::Default


Module: ActiveSupport::Testing::Default

Module
ActiveSupport::Testing::Default
In: activesupport/lib/active_support/testing/default.rb
Methods
  • run
Public Instance methods
run(*args)

[ show source ]

   # File activesupport/lib/active_support/testing/default.rb, line 4
4:       def run(*args)
5:         #method_name appears to be a symbol on 1.8.4 and a string on 1.8.6
6:         return if @method_name.to_s == "default_test"
7:         super
8:       end


Class: BlankSlate

Class
BlankSlate
In: | activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb
Parent: | Object

BlankSlate provides an abstract base class with no predefined methods (except for __send__ and __id__). BlankSlate is useful as a base class when writing classes that depend upon method_missing (e.g. dynamic proxies).

Methods
  • find_hidden_method
  • hide
  • reveal
Public Class methods
find_hidden_method(name)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 31
31:     def find_hidden_method(name)
32:       @hidden_methods ||= {}
33:       @hidden_methods[name] || superclass.find_hidden_method(name)
34:     end
hide(name)

Hide the method named name in the BlankSlate class. Don‘t hide instance_eval or any method beginning with "__".

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 22
22:     def hide(name)
23:       if instance_methods.include?(name.to_s) and
24:         name !~ /^(__|instance_eval)/
25:         @hidden_methods ||= {}
26:         @hidden_methods[name.to_sym] = instance_method(name)
27:         undef_method name
28:       end
29:     end
reveal(name)

Redefine a previously hidden method so that it may be called on a blank slate object.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 38
38:     def reveal(name)
39:       bound_method = nil
40:       unbound_method = find_hidden_method(name)
41:       fail "Don't know how to reveal method '#{name}'" unless unbound_method
42:       define_method(name) do |*args|
43:         bound_method ||= unbound_method.bind(self)
44:         bound_method.call(*args)
45:       end
46:     end


Module: Builder

Module
Builder
In: activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb
Methods
  • check_for_name_collision
Classes and Modules
Class Builder::CSS
Class Builder::IllegalBlockError
Class Builder::XmlBase
Class Builder::XmlEvents
Class Builder::XmlMarkup
Constants
BlankSlate = ::BlankSlate
Public Class methods
check_for_name_collision(klass, method_name, defined_constant=nil)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb, line 12
12:   def self.check_for_name_collision(klass, method_name, defined_constant=nil)
13:     if klass.instance_methods.include?(method_name.to_s)
14:       fail RuntimeError,
15:         "Name Collision: Method '#{method_name}' is already defined in #{klass}"
16:     end
17:   end


Class: Builder::CSS

Class
Builder::CSS
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb
Parent: | BlankSlate

Create a Cascading Style Sheet (CSS) using Ruby.

Example usage:

  css = Builder::CSS.new

  text_color      = '#7F7F7F'
  preferred_fonts = 'Helvetica, Arial, sans_serif'

  css.comment! 'This is our stylesheet'
  css.body {
    background_color '#FAFAFA'
    font_size        'small'
    font_family      preferred_fonts
    color            text_color
  }

  css.id!('navbar') {
    width            '500px'
  }

  css.class!('navitem') {
    color            'red'
  }

  css.a :hover {
    text_decoration  'underline'
  }

  css.div(:id => 'menu') {
    background       'green'
  }

  css.div(:class => 'foo') {
    background       'red'
  }

This will yield the following stylesheet:

  /* This is our stylesheet */
  body {
    background_color: #FAFAFA;
    font_size:        small;
    font_family:      Helvetica, Arial, sans_serif;
    color:            #7F7F7F;
  }

  #navbar {
    width:            500px;
  }

  .navitem {
    color:            red;
  }

  a:hover {
    text_decoration:  underline;
  }

  div#menu {
    background:       green;
  }

  div.foo {
    background:       red;
  }
Methods
  • +
  • >
  • >>
  • class!
  • comment!
  • group!
  • id!
  • method_missing
  • new
  • nil?
  • store!
  • target!
  • |
Public Class methods
new(indent=2)

Create a CSS builder.

out: | Object receiving the markup.1 out must respond to <<.
indent: | Number of spaces used for indentation (0 implies no indentation and no line breaks).

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 101
101:     def initialize(indent=2)
102:       @indent      = indent
103:       @target      = []
104:       @parts       = []
105:       @library     = {}
106:     end
Public Instance methods
+(part)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 108
108:     def +(part)
109:       _join_with_op! '+'
110:       self
111:     end
>(part)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 118
118:     def >(part)
119:       _join_with_op! '>'
120:       self
121:     end
>>(part)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 113
113:     def >>(part)
114:       _join_with_op! ''
115:       self
116:     end
class!(arg, &block)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 145
145:     def class!(arg, &block)
146:       _start_container('.'+arg.to_s, nil, block_given?)
147:       _css_block(block) if block
148:       _unify_block
149:       self
150:     end
comment!(comment_text)

Create a comment string in the output.

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 134
134:     def comment!(comment_text)
135:       @target << "/* #{comment_text} */\n"
136:     end
group!(*args, &block)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 156
156:     def group!(*args, &block)
157:       args.each do |arg|
158:         if arg.is_a?(Symbol)
159:           instance_eval(&@library[arg])
160:         else
161:           instance_eval(&arg)
162:         end
163:         _text ', ' unless arg == args.last
164:       end
165:       if block
166:         _css_block(block)
167:         _unify_block
168:       end
169:     end
id!(arg, &block)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 138
138:     def id!(arg, &block)
139:       _start_container('#'+arg.to_s, nil, block_given?)
140:       _css_block(block) if block
141:       _unify_block
142:       self
143:     end
method_missing(sym, *args, &block)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 171
171:     def method_missing(sym, *args, &block)
172:       sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
173:       if block
174:         _start_container(sym, args.first)
175:         _css_block(block)
176:         _unify_block
177:       elsif @in_block
178:         _indent
179:         _css_line(sym, *args)
180:         _newline
181:         return self
182:       else
183:         _start_container(sym, args.first, false)
184:         _unify_block
185:       end
186:       self
187:     end
nil?()

"Cargo culted" from Jim who also "cargo culted" it. See xmlbase.rb.

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 190
190:     def nil?
191:       false
192:     end
store!(sym, &block)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 152
152:     def store!(sym, &block)
153:       @library[sym] = block.to_proc
154:     end
target!()

Return the target of the builder

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 129
129:     def target!
130:       @target * ''
131:     end
|(part)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 123
123:     def |(part)
124:       _join_with_op! ','
125:       self
126:     end


Class: Builder::IllegalBlockError

Class
Builder::IllegalBlockError
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb
Parent: | RuntimeError

Generic error for builder


Class: Builder::XmlBase

Class
Builder::XmlBase
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb
Parent: | BlankSlate

XmlBase is a base class for building XML builders. See Builder::XmlMarkup and Builder::XmlEvents for examples.

Methods
  • <<
  • method_missing
  • new
  • nil?
  • tag!
  • text!
Public Class methods
new(indent=0, initial=0)

Create an XML markup builder.

out: | Object receiving the markup. out must respond to <<.
indent: | Number of spaces used for indentation (0 implies no indentation and no line breaks).
initial: | Level of initial indentation.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 22
22:     def initialize(indent=0, initial=0)
23:       @indent = indent
24:       @level  = initial
25:     end
Public Instance methods
<<(text)

Append text to the output target without escaping any markup. May be used within the markup brackets as:

  builder.p { |x| x << "<br/>HI" }   #=>  <p><br/>HI</p>

This is useful when using non-builder enabled software that generates strings. Just insert the string directly into the builder without changing the inserted markup.

It is also useful for stacking builder objects. Builders only use << to append to the target, so by supporting this method/operation builders can use other builders as their targets.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 97
97:     def <<(text)
98:       _text(text)
99:     end
method_missing(sym, *args, &block)

Create XML markup based on the name of the method. This method is never invoked directly, but is called for each markup method in the markup block.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 37
37:     def method_missing(sym, *args, &block)
38:       text = nil
39:       attrs = nil
40:       sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
41:       args.each do |arg|
42:         case arg
43:         when Hash
44:           attrs ||= {}
45:           attrs.merge!(arg)
46:         else
47:           text ||= ''
48:           text << arg.to_s
49:         end
50:       end
51:       if block
52:         unless text.nil?
53:           raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
54:         end
55:         _indent
56:         _start_tag(sym, attrs)
57:         _newline
58:         _nested_structures(block)
59:         _indent
60:         _end_tag(sym)
61:         _newline
62:       elsif text.nil?
63:         _indent
64:         _start_tag(sym, attrs, true)
65:         _newline
66:       else
67:         _indent
68:         _start_tag(sym, attrs)
69:         text! text
70:         _end_tag(sym)
71:         _newline
72:       end
73:       @target
74:     end
nil?()

For some reason, nil? is sent to the XmlMarkup object. If nil? is not defined and method_missing is invoked, some strange kind of recursion happens. Since nil? won‘t ever be an XML tag, it is pretty safe to define it here. (Note: this is an example of cargo cult programming, cf. fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 107
107:     def nil?
108:       false
109:     end
tag!(sym, *args, &block)

Create a tag named sym. Other than the first argument which is the tag name, the arguments are the same as the tags implemented via method_missing.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 30
30:     def tag!(sym, *args, &block)
31:       method_missing(sym.to_sym, *args, &block)
32:     end
text!(text)

Append text to the output target. Escape any markup. May be used within the markup brackets as:

  builder.p { |b| b.br; b.text! "HI" }   #=>  <p><br/>HI</p>

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb, line 80
80:     def text!(text)
81:       _text(_escape(text))
82:     end


Class: Builder::XmlEvents

Class
Builder::XmlEvents
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb
Parent: | XmlMarkup

Create a series of SAX-like XML events (e.g. start_tag, end_tag) from the markup code. XmlEvent objects are used in a way similar to XmlMarkup objects, except that a series of events are generated and passed to a handler rather than generating character-based markup.

Usage:

  xe = Builder::XmlEvents.new(hander)
  xe.title("HI")    # Sends start_tag/end_tag/text messages to the handler.

Indentation may also be selected by providing value for the indentation size and initial indentation level.

  xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level)

XML Event Handler

The handler object must expect the following events.

start_tag(tag, attrs)
Announces that a new tag has been found. tag is the name of the tag and attrs is a hash of attributes for the tag.
end_tag(tag)
Announces that an end tag for tag has been found.
text(text)
Announces that a string of characters (text) has been found. A series of characters may be broken up into more than one text call, so the client cannot assume that a single callback contains all the text data.
Methods
  • _end_tag
  • _start_tag
  • text!
Public Instance methods
_end_tag(sym)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb, line 58
58:     def _end_tag(sym)
59:       @target.end_tag(sym)
60:     end
_start_tag(sym, attrs, end_too=false)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb, line 53
53:     def _start_tag(sym, attrs, end_too=false)
54:       @target.start_tag(sym, attrs)
55:       _end_tag(sym) if end_too
56:     end
text!(text)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb, line 49
49:     def text!(text)
50:       @target.text(text)
51:     end


Class: Builder::XmlMarkup

Class
Builder::XmlMarkup
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb
Parent: | XmlBase

Create XML markup easily. All (well, almost all) methods sent to an XmlMarkup object will be translated to the equivalent XML markup. Any method with a block will be treated as an XML markup tag with nested markup in the block.

Examples will demonstrate this easier than words. In the following, xm is an XmlMarkup object.

  xm.em("emphasized")             # => <em>emphasized</em>
  xm.em { xmm.b("emp & bold") }   # => <em><b>emph &amp; bold</b></em>
  xm.a("A Link", "href"=>"http://onestepback.org")
                                  # => <a href="http://onestepback.org">A Link</a>
  xm.div { br }                    # => <div><br/></div>
  xm.target("name"=>"compile", "option"=>"fast")
                                  # => <target option="fast" name="compile"\>
                                  # NOTE: order of attributes is not specified.

  xm.instruct!                   # <?xml version="1.0" encoding="UTF-8"?>
  xm.html {                      # <html>
    xm.head {                    #   <head>
      xm.title("History")        #     <title>History</title>
    }                            #   </head>
    xm.body {                    #   <body>
      xm.comment! "HI"           #     <! -- HI -->
      xm.h1("Header")            #     <h1>Header</h1>
      xm.p("paragraph")          #     <p>paragraph</p>
    }                            #   </body>
  }                              # </html>

Notes:

  • The order that attributes are inserted in markup tags is undefined.
  • Sometimes you wish to insert text without enclosing tags. Use the text! method to accomplish this.

    Example:

      xm.div {                          # <div>
    xm.text! "line"; xm.br          #   line<br/>
    xm.text! "another line"; xmbr   #    another line<br/>
  }                                 # </div>
  • The special XML characters <, >, and & are converted to &lt;, &gt; and &amp; automatically. Use the << operation to insert text without modification.
  • Sometimes tags use special characters not allowed in ruby identifiers. Use the tag! method to handle these cases.

    Example:

      xml.tag!("SOAP:Envelope") { ... }

    will produce …

      <SOAP:Envelope> ... </SOAP:Envelope>"

    tag! will also take text and attribute arguments (after the tag name) like normal markup methods. (But see the next bullet item for a better way to handle XML namespaces).

  • Direct support for XML namespaces is now available. If the first argument to a tag call is a symbol, it will be joined to the tag to produce a namespace:tag combination. It is easier to show this than describe it.
      xml.SOAP :Envelope do ... end

    Just put a space before the colon in a namespace to produce the right form for builder (e.g. "SOAP:Envelope" => "xml.SOAP :Envelope")

  • XmlMarkup builds the markup in any object (called a target) that accepts the << method. If no target is given, then XmlMarkup defaults to a string target.

    Examples:

      xm = Builder::XmlMarkup.new
  result = xm.title("yada")
  # result is a string containing the markup.

  buffer = ""
  xm = Builder::XmlMarkup.new(buffer)
  # The markup is appended to buffer (using <<)

  xm = Builder::XmlMarkup.new(STDOUT)
  # The markup is written to STDOUT (using <<)

  xm = Builder::XmlMarkup.new
  x2 = Builder::XmlMarkup.new(:target=>xm)
  # Markup written to +x2+ will be send to +xm+.
  • Indentation is enabled by providing the number of spaces to indent for each level as a second argument to XmlBuilder.new. Initial indentation may be specified using a third parameter.

    Example:

      xm = Builder.new(:indent=>2)
  # xm will produce nicely formatted and indented XML.

  xm = Builder.new(:indent=>2, :margin=>4)
  # xm will produce nicely formatted and indented XML with 2
  # spaces per indent and an over all indentation level of 4.

  builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
  builder.name { |b| b.first("Jim"); b.last("Weirich) }
  # prints:
  #     <name>
  #       <first>Jim</first>
  #       <last>Weirich</last>
  #     </name>
  • The instance_eval implementation which forces self to refer to the message receiver as self is now obsolete. We now use normal block calls to execute the markup block. This means that all markup methods must now be explicitly send to the xml builder. For instance, instead of
       xml.div { strong("text") }

    you need to write:

       xml.div { xml.strong("text") }

    Although more verbose, the subtle change in semantics within the block was found to be prone to error. To make this change a little less cumbersome, the markup block now gets the markup object sent as an argument, allowing you to use a shorter alias within the block.

    For example:

      xml_builder = Builder::XmlMarkup.new
  xml_builder.div { |xml|
    xml.stong("text")
  }
Methods
  • cdata!
  • comment!
  • declare!
  • instruct!
  • new
  • target!
Public Class methods
new(options={})

Create an XML markup builder. Parameters are specified by an option hash.

:target=>target_object: | Object receiving the markup. out must respond to the << operator. The default is a plain string target.
:indent=>indentation: | Number of spaces used for indentation. The default is no indentation and no line breaks.
:margin=>initial_indentation_level: | Amount of initial indentation (specified in levels, not spaces).
:escape_attrs=><b>OBSOLETE</em>: | The :escape_attrs option is no longer supported by builder (and will be quietly ignored). String attribute values are now automatically escaped. If you need unescaped attribute values (perhaps you are using entities in the attribute values), then give the value as a Symbol. This allows much finer control over escaping attribute values.

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 185
185:     def initialize(options={})
186:       indent = options[:indent] || 0
187:       margin = options[:margin] || 0
188:       super(indent, margin)
189:       @target = options[:target] || ""
190:     end
Public Instance methods
cdata!(text)

Insert a CDATA section into the XML markup.

For example:

   xml.cdata!("text to be included in cdata")
       #=> <![CDATA[text to be included in cdata]]>

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 259
259:     def cdata!(text)
260:       _ensure_no_block block_given?
261:       _special("<![CDATA[", "]]>", text, nil)
262:     end
comment!(comment_text)

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 197
197:     def comment!(comment_text)
198:       _ensure_no_block block_given?
199:       _special("<!-- ", " -->", comment_text, nil)
200:     end
declare!(inst, *args, &block)

Insert an XML declaration into the XML markup.

For example:

  xml.declare! :ELEMENT, :blah, "yada"
      # => <!ELEMENT blah "yada">

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 208
208:     def declare!(inst, *args, &block)
209:       _indent
210:       @target << "<!#{inst}"
211:       args.each do |arg|
212:         case arg
213:         when String
214:           @target << %{ "#{arg}"} # " WART
215:         when Symbol
216:           @target << " #{arg}"
217:         end
218:       end
219:       if block_given?
220:         @target << " ["
221:         _newline
222:         _nested_structures(block)
223:         @target << "]"
224:       end
225:       @target << ">"
226:       _newline
227:     end
instruct!(directive_tag=:xml, attrs={})

Insert a processing instruction into the XML markup. E.g.

For example:

   xml.instruct!
       #=> <?xml version="1.0" encoding="UTF-8"?>
   xml.instruct! :aaa, :bbb=>"ccc"
       #=> <?aaa bbb="ccc"?>

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 238
238:     def instruct!(directive_tag=:xml, attrs={})
239:       _ensure_no_block block_given?
240:       if directive_tag == :xml
241:         a = { :version=>"1.0", :encoding=>"UTF-8" }
242:         attrs = a.merge attrs
243:       end
244:       _special(
245:       "<?#{directive_tag}",
246:       "?>",
247:       nil,
248:       attrs,
249:       [:version, :encoding, :standalone])
250:     end
target!()

Return the target of the builder.

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb, line 193
193:     def target!
194:       @target
195:     end


Class: DateTime

Class
DateTime
In: | activesupport/lib/active_support/core_ext/date_time.rb activesupport/lib/active_support/json/encoders/date_time.rb
Parent: | Object
Included Modules
  • ActiveSupport::CoreExtensions::Time::Behavior
  • ActiveSupport::CoreExtensions::DateTime::Calculations
  • ActiveSupport::CoreExtensions::DateTime::Conversions


Class: DispatchServlet

Class
DispatchServlet
In: | railties/lib/webrick_server.rb
Parent: | WEBrick::HTTPServlet::AbstractServlet

A custom dispatch servlet for use with WEBrick. It dispatches requests (using the Rails Dispatcher) to the appropriate controller/action. By default, it restricts WEBrick to a managing a single Rails request at a time, but you can change this behavior by setting ActionController::Base.allow_concurrency to true.

Methods
  • dispatch
Constants
REQUEST_MUTEX = Mutex.new
Public Class methods
dispatch(options = {})

Start the WEBrick server with the given options, mounting the DispatchServlet at /.

[ show source ]

    # File railties/lib/webrick_server.rb, line 50
50:   def self.dispatch(options = {})
51:     Socket.do_not_reverse_lookup = true # patch for OS X
52:
53:     params = { :Port        => options[:port].to_i,
54:                :ServerType  => options[:server_type],
55:                :BindAddress => options[:ip] }
56:     params[:MimeTypes] = options[:mime_types] if options[:mime_types]
57:
58:     server = WEBrick::HTTPServer.new(params)
59:     server.mount('/', DispatchServlet, options)
60:
61:     trap("INT") { server.shutdown }
62:     server.start
63:   end


Class: ERB

Class
ERB
In: | actionpack/lib/action_view/template_handlers/erb.rb
Parent: | Object
Classes and Modules
Module ERB::Util


Module: ERB::Util

Module
ERB::Util
In: actionpack/lib/action_view/template_handlers/erb.rb
Methods
  • html_escape
Constants
HTML_ESCAPE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' }
Public Instance methods
html_escape(s)

[ show source ]

   # File actionpack/lib/action_view/template_handlers/erb.rb, line 7
7:     def html_escape(s)
8:       s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
9:     end


Module: Enumerable

Module
Enumerable
In: activesupport/lib/active_support/core_ext/enumerable.rb activesupport/lib/active_support/json/encoders/enumerable.rb
Methods
  • group_by
  • index_by
  • sum
Public Instance methods
group_by() {|element| ...}

Collect an enumerable into sets, grouped by the result of a block. Useful, for example, for grouping records by date.

e.g.

  latest_transcripts.group_by(&:day).each do |day, transcripts|
    p "#{day} -> #{transcripts.map(&:class) * ', '}"
  end
  "2006-03-01 -> Transcript"
  "2006-02-28 -> Transcript"
  "2006-02-27 -> Transcript, Transcript"
  "2006-02-26 -> Transcript, Transcript"
  "2006-02-25 -> Transcript"
  "2006-02-24 -> Transcript, Transcript"
  "2006-02-23 -> Transcript"

[ show source ]

    # File activesupport/lib/active_support/core_ext/enumerable.rb, line 17
17:   def group_by
18:     inject({}) do |groups, element|
19:       (groups[yield(element)] ||= []) << element
20:       groups
21:     end
22:   end
index_by() {|elem| ...}

Convert an enumerable to a hash. Examples:

  people.index_by(&:login)
    => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
  people.index_by { |person| "#{person.first_name} #{person.last_name}" }
    => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}

[ show source ]

    # File activesupport/lib/active_support/core_ext/enumerable.rb, line 56
56:   def index_by
57:     inject({}) do |accum, elem|
58:       accum[yield(elem)] = elem
59:       accum
60:     end
61:   end
sum(identity = 0, &block)

Calculates a sum from the elements. Examples:

 payments.sum { |p| p.price * p.tax_rate }
 payments.sum(&:price)

This is instead of payments.inject { |sum, p| sum + p.price }

Also calculates sums without the use of a block:

  [5, 15, 10].sum # => 30

The default identity (sum of an empty list) is zero. However, you can override this default:

[].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)

[ show source ]

    # File activesupport/lib/active_support/core_ext/enumerable.rb, line 39
39:   def sum(identity = 0, &block)
40:     return identity unless size > 0
41:
42:     if block_given?
43:       map(&block).sum
44:     else
45:       inject { |sum, element| sum + element }
46:     end
47:   end


Class: File

Class
File
In: |
Parent: | IO
Methods
  • atomic_write
Public Class methods
atomic_write(file_name, temp_dir = Dir.tmpdir) {|temp_file| ...}

Write to a file atomically. Useful for situations where you don‘t want other processes or threads to see half-written files.

 File.atomic_write("important.file") do |file|
   file.write("hello")
 end

If your temp directory is not on the same filesystem as the file you‘re trying to write, you can provide a different temporary directory.

File.atomic_write("/data/something.imporant", "/data/tmp") do |f|

  file.write("hello")

end

[ show source ]

    # File activesupport/lib/active_support/core_ext/file.rb, line 16
16: def File.atomic_write(file_name, temp_dir = Dir.tmpdir)
17:   temp_file = Tempfile.new(File.basename(file_name), temp_dir)
18:   yield temp_file
19:   temp_file.close
20:   File.rename(temp_file.path, file_name)
21: end


Class: Fixnum

Class
Fixnum
In: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb
Parent: | Object

Enhance the Fixnum class with a XML escaped character conversion.

Methods
  • xchr
Constants
XChar = Builder::XChar if ! defined?(XChar)
Public Instance methods
xchr()

XML escaped version of chr

[ show source ]

     # File activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb, line 93
 93:   def xchr
 94:     n = XChar::CP1252[self] || self
 95:     case n when *XChar::VALID
 96:       XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
 97:     else
 98:       '*'
 99:     end
100:   end


Class: Fixtures

Class
Fixtures
In: | activerecord/lib/active_record/fixtures.rb
Parent: | YAML::Omap

Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavors:

  1.  YAML fixtures
  2.  CSV fixtures
  3.  Single-file fixtures

YAML fixtures

This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.

Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed by Test::Unit::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:

  rubyonrails:
    id: 1
    name: Ruby on Rails
    url: http://www.rubyonrails.org

  google:
    id: 2
    name: Google
    url: http://www.google.com

This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing pleasure.

Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See yaml.org/type/omap.html for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table. This is commonly needed for tree structures. Example:

   --- !omap
   - parent:
       id:         1
       parent_id:  NULL
       title:      Parent
   - child:
       id:         2
       parent_id:  1
       title:      Child

CSV fixtures

Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")

The format of this type of fixture file is much more compact than the others, but also a little harder to read by us humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised of the actual data (1 per line). Here‘s an example:

  id, name, url
  1, Ruby On Rails, http://www.rubyonrails.org
  2, Google, http://www.google.com

Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you need to use a double quote character, you must escape it with another double quote.

Another unique attribute of the CSV fixture is that it has no fixture name like the other two formats. Instead, the fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called "web_site_2".

Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you have existing data somewhere already.

Single-file fixtures

This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats. Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory appointed by Test::Unit::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just put your files in <your-rails-app>/test/fixtures/<your-model-name>/ — like <your-rails-app>/test/fixtures/web_sites/ for the WebSite model).

Each text file placed in this directory represents a "record". Usually these types of fixtures are named without extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here‘s what the above example might look like:

  web_sites/google
  web_sites/yahoo.txt
  web_sites/ruby-on-rails

The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax of "name => value". Here‘s an example of the ruby-on-rails fixture above:

  id => 1
  name => Ruby on Rails
  url => http://www.rubyonrails.org

Using Fixtures

Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the fixtures, but first let‘s take a look at a sample unit test:

  require 'web_site'

  class WebSiteTest < Test::Unit::TestCase
    def test_web_site_count
      assert_equal 2, WebSite.count
    end
  end

As it stands, unless we pre-load the web_site table in our database with two records, this test will fail. Here‘s the easiest way to add fixtures to the database:

  ...
  class WebSiteTest < Test::Unit::TestCase
    fixtures :web_sites # add more by separating the symbols with commas
  ...

By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here though), we trigger the testing environment to automatically load the appropriate fixtures into the database before each test. To ensure consistent data, the environment deletes the fixtures before running the load.

In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable of the test case. It is named after the symbol… so, in our example, there would be a hash available called @web_sites. This is where the "fixture name" comes into play.

On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. So for the YAML fixtures, we‘d get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:

  # test if the object created from the fixture data has the same attributes as the data itself
  def test_find
    assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
  end

As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return "www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual fixtures available as instance variables @web_site_1 and @web_site_2.

If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.

  - to completely disable instantiated fixtures:
      self.use_instantiated_fixtures = false

  - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
      self.use_instantiated_fixtures = :no_instances

Even if auto-instantiated fixtures are disabled, you can still access them by name via special dynamic methods. Each method has the same name as the model, and accepts the name of the fixture to instantiate:

  fixtures :web_sites

  def test_find
    assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
  end

Dynamic fixtures with ERb

Some times you don‘t care about the content of the fixtures as much as you care about the volume. In these cases, you can mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:

<% for i in 1..1000 %> fix_<%= i %>:

  id: <%= i %>
  name: guy_<%= 1 %>

<% end %>

This will create 1000 very simple YAML fixtures.

Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. This is however a feature to be used with some caution. The point of fixtures are that they‘re stable units of predictable sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.

Transactional fixtures

TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case. They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.

  class FooTest < Test::Unit::TestCase
    self.use_transactional_fixtures = true
    self.use_instantiated_fixtures = false

    fixtures :foos

    def test_godzilla
      assert !Foo.find(:all).empty?
      Foo.destroy_all
      assert Foo.find(:all).empty?
    end

    def test_godzilla_aftermath
      assert !Foo.find(:all).empty?
    end
  end

If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures, then you may omit all fixtures declarations in your test cases since all the data‘s already there and every case rolls back its changes.

In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide access to fixture data for every table that has been loaded through fixtures (depending on the value of use_instantiated_fixtures)

When not to use transactional fixtures:

  1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
     particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
     the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
  2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
     Use InnoDB, MaxDB, or NDB instead.

Advanced YAML Fixtures

YAML fixtures that don‘t specify an ID get some extra features:

  • Stable, autogenerated ID‘s
  • Label references for associations (belongs_to, has_one, has_many)
  • HABTM associations as inline lists
  • Autofilled timestamp columns
  • Fixture label interpolation
  • Support for YAML defaults

Stable, autogenerated ID‘s

Here, have a monkey fixture:

  george:
    id: 1
    name: George the Monkey

  reginald:
    id: 2
    name: Reginald the Pirate

Each of these fixtures has two unique identifiers: one for the database and one for the humans. Why don‘t we generate the primary key instead? Hashing each fixture‘s label yields a consistent ID:

  george: # generated id: 503576764
    name: George the Monkey

  reginald: # generated id: 324201669
    name: Reginald the Pirate

ActiveRecord looks at the fixture‘s model class, discovers the correct primary key, and generates it right before inserting the fixture into the database.

The generated ID for a given label is constant, so we can discover any fixture‘s ID without loading anything, as long as we know the label.

Label references for associations (belongs_to, has_one, has_many)

Specifying foreign keys in fixtures can be very fragile, not to mention difficult to read. Since ActiveRecord can figure out the ID of any fixture from its label, you can specify FK‘s by label instead of ID.

belongs_to

Let‘s break out some more monkeys and pirates.

  ### in pirates.yml

  reginald:
    id: 1
    name: Reginald the Pirate
    monkey_id: 1

  ### in monkeys.yml

  george:
    id: 1
    name: George the Monkey
    pirate_id: 1

Add a few more monkeys and pirates and break this into multiple files, and it gets pretty hard to keep track of what‘s going on. Let‘s use labels instead of ID‘s:

  ### in pirates.yml

  reginald:
    name: Reginald the Pirate
    monkey: george

  ### in monkeys.yml

  george:
    name: George the Monkey
    pirate: reginald

Pow! All is made clear. ActiveRecord reflects on the fixture‘s model class, finds all the belongs_to associations, and allows you to specify a target label for the association (monkey: george) rather than a target id for the FK (monkey_id: 1).

Polymorphic belongs_to

Supporting polymorphic relationships is a little bit more complicated, since ActiveRecord needs to know what type your association is pointing at. Something like this should look familiar:

  ### in fruit.rb

  belongs_to :eater, :polymorphic => true

  ### in fruits.yml

  apple:
    id: 1
    name: apple
    eater_id: 1
    eater_type: Monkey

Can we do better? You bet!

  apple:
    eater: george (Monkey)

Just provide the polymorphic target type and ActiveRecord will take care of the rest.

has_and_belongs_to_many

Time to give our monkey some fruit.

  ### in monkeys.yml

  george:
    id: 1
    name: George the Monkey
    pirate_id: 1

  ### in fruits.yml

  apple:
    id: 1
    name: apple

  orange:
    id: 2
    name: orange

  grape:
    id: 3
    name: grape

  ### in fruits_monkeys.yml

  apple_george:
    fruit_id: 1
    monkey_id: 1

  orange_george:
    fruit_id: 2
    monkey_id: 1

  grape_george:
    fruit_id: 3
    monkey_id: 1

Let‘s make the HABTM fixture go away.

  ### in monkeys.yml

  george:
    name: George the Monkey
    pirate: reginald
    fruits: apple, orange, grape

  ### in fruits.yml

  apple:
    name: apple

  orange:
    name: orange

  grape:
    name: grape

Zap! No more fruits_monkeys.yml file. We‘ve specified the list of fruits on George‘s fixture, but we could‘ve just as easily specified a list of monkeys on each fruit. As with belongs_to, ActiveRecord reflects on the fixture‘s model class and discovers the has_and_belongs_to_many associations.

Autofilled timestamp columns

If your table/model specifies any of ActiveRecord‘s standard timestamp columns (created_at, created_on, updated_at, updated_on), they will automatically be set to Time.now.

If you‘ve set specific values, they‘ll be left alone.

Fixture label interpolation

The label of the current fixture is always available as a column value:

  geeksomnia:
    name: Geeksomnia's Account
    subdomain: $LABEL

Also, sometimes (like when porting older join table fixtures) you‘ll need to be able to get ahold of the identifier for a given label. ERB to the rescue:

  george_reginald:
    monkey_id: <%= Fixtures.identify(:reginald) %>
    pirate_id: <%= Fixtures.identify(:george) %>

Support for YAML defaults

You probably already know how to use YAML to set and reuse defaults in your +database.yml+ file,. You can use the same technique in your fixtures:

  DEFAULTS: &DEFAULTS
    created_on: <%= 3.weeks.ago.to_s(:db) %>

  first:
    name: Smurf
    <<: *DEFAULTS

  second:
    name: Fraggle
    <<: *DEFAULTS

Any fixture labeled "DEFAULTS" is safely ignored.

Methods
  • cache_fixtures
  • cache_for_connection
  • cached_fixtures
  • create_fixtures
  • delete_existing_fixtures
  • fixture_is_cached?
  • identify
  • insert_fixtures
  • instantiate_all_loaded_fixtures
  • instantiate_fixtures
  • new
  • reset_cache
Constants
DEFAULT_FILTER_RE = /\.ya?ml$/
Attributes
[R] table_name
Public Class methods
cache_fixtures(connection, fixtures)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 469
469:   def self.cache_fixtures(connection, fixtures)
470:     cache_for_connection(connection).update(fixtures.index_by(&:table_name))
471:   end
cache_for_connection(connection)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 451
451:   def self.cache_for_connection(connection)
452:     @@all_cached_fixtures[connection.object_id] ||= {}
453:     @@all_cached_fixtures[connection.object_id]
454:   end
cached_fixtures(connection, keys_to_fetch = nil)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 460
460:   def self.cached_fixtures(connection, keys_to_fetch = nil)
461:     if keys_to_fetch
462:       fixtures = cache_for_connection(connection).values_at(*keys_to_fetch)
463:     else
464:       fixtures = cache_for_connection(connection).values
465:     end
466:     fixtures.size > 1 ? fixtures : fixtures.first
467:   end
create_fixtures(fixtures_directory, table_names, class_names = {}) {|: ActiveRecord::Base.connection| ...}

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 497
497:   def self.create_fixtures(fixtures_directory, table_names, class_names = {})
498:     table_names = [table_names].flatten.map { |n| n.to_s }
499:     connection  = block_given? ? yield : ActiveRecord::Base.connection
500:
501:     table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
502:
503:     unless table_names_to_fetch.empty?
504:       ActiveRecord::Base.silence do
505:         connection.disable_referential_integrity do
506:           fixtures_map = {}
507:
508:           fixtures = table_names_to_fetch.map do |table_name|
509:             fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
510:           end
511:
512:           all_loaded_fixtures.update(fixtures_map)
513:
514:           connection.transaction(Thread.current['open_transactions'].to_i == 0) do
515:             fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
516:             fixtures.each { |fixture| fixture.insert_fixtures }
517:
518:             # Cap primary key sequences to max(pk).
519:             if connection.respond_to?(:reset_pk_sequence!)
520:               table_names.each do |table_name|
521:                 connection.reset_pk_sequence!(table_name)
522:               end
523:             end
524:           end
525:
526:           cache_fixtures(connection, fixtures)
527:         end
528:       end
529:     end
530:     cached_fixtures(connection, table_names)
531:   end
fixture_is_cached?(connection, table_name)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 456
456:   def self.fixture_is_cached?(connection, table_name)
457:     cache_for_connection(connection)[table_name]
458:   end
identify(label)

Returns a consistent identifier for label. This will always be a positive integer, and will always be the same for a given label, assuming the same OS, platform, and version of Ruby.

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 536
536:   def self.identify(label)
537:     label.to_s.hash.abs
538:   end
instantiate_all_loaded_fixtures(object, load_instances = true)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 488
488:   def self.instantiate_all_loaded_fixtures(object, load_instances = true)
489:     all_loaded_fixtures.each do |table_name, fixtures|
490:       Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
491:     end
492:   end
instantiate_fixtures(object, table_name, fixtures, load_instances = true)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 473
473:   def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
474:     object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
475:     if load_instances
476:       ActiveRecord::Base.silence do
477:         fixtures.each do |name, fixture|
478:           begin
479:             object.instance_variable_set "@#{name}", fixture.find
480:           rescue FixtureClassNotFound
481:             nil
482:           end
483:         end
484:       end
485:     end
486:   end
new(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 542
542:   def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
543:     @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
544:     @class_name = class_name ||
545:                   (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
546:     @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
547:     @table_name = class_name.table_name if class_name.respond_to?(:table_name)
548:     @connection = class_name.connection if class_name.respond_to?(:connection)
549:     read_fixture_files
550:   end
reset_cache(connection = nil)

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 446
446:   def self.reset_cache(connection = nil)
447:     connection ||= ActiveRecord::Base.connection
448:     @@all_cached_fixtures[connection.object_id] = {}
449:   end
Public Instance methods
delete_existing_fixtures()

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 552
552:   def delete_existing_fixtures
553:     @connection.delete "DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
554:   end
insert_fixtures()

[ show source ]

     # File activerecord/lib/active_record/fixtures.rb, line 556
556:   def insert_fixtures
557:     now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
558:     now = now.to_s(:db)
559:
560:     # allow a standard key to be used for doing defaults in YAML
561:     delete(assoc("DEFAULTS"))
562:
563:     # track any join tables we need to insert later
564:     habtm_fixtures = Hash.new do |h, habtm|
565:       h[habtm] = HabtmFixtures.new(@connection, habtm.options[:join_table], nil, nil)
566:     end
567:
568:     each do |label, fixture|
569:       row = fixture.to_hash
570:
571:       if model_class && model_class < ActiveRecord::Base
572:         # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
573:         if model_class.record_timestamps
574:           timestamp_column_names.each do |name|
575:             row[name] = now unless row.key?(name)
576:           end
577:         end
578:
579:         # interpolate the fixture label
580:         row.each do |key, value|
581:           row[key] = label if value == "$LABEL"
582:         end
583:
584:         # generate a primary key if necessary
585:         if has_primary_key_column? && !row.include?(primary_key_name)
586:           row[primary_key_name] = Fixtures.identify(label)
587:         end
588:
589:         # If STI is used, find the correct subclass for association reflection
590:         reflection_class =
591:           if row.include?(inheritance_column_name)
592:             row[inheritance_column_name].constantize rescue model_class
593:           else
594:             model_class
595:           end
596:
597:         reflection_class.reflect_on_all_associations.each do |association|
598:           case association.macro
599:           when :belongs_to
600:             # Do not replace association name with association foreign key if they are named the same
601:             fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
602:
603:             if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
604:               if association.options[:polymorphic]
605:                 if value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
606:                   target_type = $1
607:                   target_type_name = (association.options[:foreign_type] || "#{association.name}_type").to_s
608:
609:                   # support polymorphic belongs_to as "label (Type)"
610:                   row[target_type_name] = target_type
611:                 end
612:               end
613:
614:               row[fk_name] = Fixtures.identify(value)
615:             end
616:           when :has_and_belongs_to_many
617:             if (targets = row.delete(association.name.to_s))
618:               targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
619:               join_fixtures = habtm_fixtures[association]
620:
621:               targets.each do |target|
622:                 join_fixtures["#{label}_#{target}"] = Fixture.new(
623:                   { association.primary_key_name => row[primary_key_name],
624:                     association.association_foreign_key => Fixtures.identify(target) }, nil)
625:               end
626:             end
627:           end
628:         end
629:       end
630:
631:       @connection.insert_fixture(fixture, @table_name)
632:     end
633:
634:     # insert any HABTM join tables we discovered
635:     habtm_fixtures.values.each do |fixture|
636:       fixture.delete_existing_fixtures
637:       fixture.insert_fixtures
638:     end
639:   end


Class: HTML::FullSanitizer

Class
HTML::FullSanitizer
In: | actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
Parent: | Sanitizer
Methods
  • process_node
  • sanitize
Public Instance methods
process_node(node, result, options)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 38
38:     def process_node(node, result, options)
39:       result << node.to_s if node.class == HTML::Text
40:     end
sanitize(text, options = {})

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 29
29:     def sanitize(text, options = {})
30:       result = super
31:       # strip any comments, and if they have a newline at the end (ie. line with
32:       # only a comment) strip that too
33:       result.gsub!(/<!--(.*?)-->[\n]?/m, "") if result
34:       # Recurse - handle all dirty nested tags
35:       result == text ? result : sanitize(result, options)
36:     end


Class: HTML::LinkSanitizer

Class
HTML::LinkSanitizer
In: | actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
Parent: | FullSanitizer
Methods
  • process_node
  • sanitizeable?
Public Instance methods
sanitizeable?(text)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 47
47:     def sanitizeable?(text)
48:       !(text.nil? || text.empty? || !((text.index("<a") || text.index("<href")) && text.index(">")))
49:     end
Protected Instance methods
process_node(node, result, options)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 52
52:     def process_node(node, result, options)
53:       result << node.to_s unless node.is_a?(HTML::Tag) && included_tags.include?(node.name)
54:     end


Class: HTML::Sanitizer

Class
HTML::Sanitizer
In: | actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
Parent: | Object
Methods
  • process_node
  • sanitize
  • sanitizeable?
  • tokenize
Public Instance methods
sanitize(text, options = {})

[ show source ]

   # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 3
3:     def sanitize(text, options = {})
4:       return text unless sanitizeable?(text)
5:       tokenize(text, options).join
6:     end
sanitizeable?(text)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 8
 8:     def sanitizeable?(text)
 9:       !(text.nil? || text.empty? || !text.index("<"))
10:     end
Protected Instance methods
process_node(node, result, options)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 23
23:     def process_node(node, result, options)
24:       result << node.to_s
25:     end
tokenize(text, options)

[ show source ]

    # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 13
13:     def tokenize(text, options)
14:       tokenizer = HTML::Tokenizer.new(text)
15:       result = []
16:       while token = tokenizer.next
17:         node = Node.parse(nil, 0, 0, token, false)
18:         process_node node, result, options
19:       end
20:       result
21:     end


Class: HTML::Selector

Class
HTML::Selector
In: | actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb
Parent: | Object

Selects HTML elements using CSS 2 selectors.

The Selector class uses CSS selector expressions to match and select HTML elements.

For example:

  selector = HTML::Selector.new "form.login[action=/login]"

creates a new selector that matches any form element with the class login and an attribute action with the value /login.

Matching Elements

Use the match method to determine if an element matches the selector.

For simple selectors, the method returns an array with that element, or nil if the element does not match. For complex selectors (see below) the method returns an array with all matched elements, of nil if no match found.

For example:

  if selector.match(element)
    puts "Element is a login form"
  end

Selecting Elements

Use the select method to select all matching elements starting with one element and going through all children in depth-first order.

This method returns an array of all matching elements, an empty array if no match is found

For example:

  selector = HTML::Selector.new "input[type=text]"
  matches = selector.select(element)
  matches.each do |match|
    puts "Found text field with name #{match.attributes['name']}"
  end

Expressions

Selectors can match elements using any of the following criteria:

  • name — Match an element based on its name (tag name). For example, p to match a paragraph. You can use * to match any element.
  • #id — Match an element based on its identifier (the id attribute). For example, #page.
  • .class — Match an element based on its class name, all class names if more than one specified.
  • [attr] — Match an element that has the specified attribute.
  • [attr=value] — Match an element that has the specified attribute and value. (More operators are supported see below)
  • :pseudo-class — Match an element based on a pseudo class, such as :nth-child and :empty.
  • :not(expr) — Match an element that does not match the negation expression.

When using a combination of the above, the element name comes first followed by identifier, class names, attributes, pseudo classes and negation in any order. Do not seprate these parts with spaces! Space separation is used for descendant selectors.

For example:

  selector = HTML::Selector.new "form.login[action=/login]"

The matched element must be of type form and have the class login. It may have other classes, but the class login is required to match. It must also have an attribute called action with the value /login.

This selector will match the following element:

  <form class="login form" method="post" action="/login">

but will not match the element:

  <form method="post" action="/logout">

Attribute Values

Several operators are supported for matching attributes:

  • name — The element must have an attribute with that name.
  • name=value — The element must have an attribute with that name and value.
  • name^=value — The attribute value must start with the specified value.
  • name$=value — The attribute value must end with the specified value.
  • name*=value — The attribute value must contain the specified value.
  • name~=word — The attribute value must contain the specified word (space separated).
  • name|=word — The attribute value must start with specified word.

For example, the following two selectors match the same element:

  #my_id
  [id=my_id]

and so do the following two selectors:

  .my_class
  [class~=my_class]

Alternatives, siblings, children

Complex selectors use a combination of expressions to match elements:

  • expr1 expr2 — Match any element against the second expression if it has some parent element that matches the first expression.
  • expr1 > expr2 — Match any element against the second expression if it is the child of an element that matches the first expression.
  • expr1 + expr2 — Match any element against the second expression if it immediately follows an element that matches the first expression.
  • expr1 ~ expr2 — Match any element against the second expression that comes after an element that matches the first expression.
  • expr1, expr2 — Match any element against the first expression, or against the second expression.

Since children and sibling selectors may match more than one element given the first element, the match method may return more than one match.

Pseudo classes

Pseudo classes were introduced in CSS 3. They are most often used to select elements in a given position:

  • :root — Match the element only if it is the root element (no parent element).
  • :empty — Match the element only if it has no child elements, and no text content.
  • :only-child — Match the element if it is the only child (element) of its parent element.
  • :only-of-type — Match the element if it is the only child (element) of its parent element and its type.
  • :first-child — Match the element if it is the first child (element) of its parent element.
  • :first-of-type — Match the element if it is the first child (element) of its parent element of its type.
  • :last-child — Match the element if it is the last child (element) of its parent element.
  • :last-of-type — Match the element if it is the last child (element) of its parent element of its type.
  • :nth-child(b) — Match the element if it is the b-th child (element) of its parent element. The value b specifies its index, starting with 1.
  • :nth-child(an+b) — Match the element if it is the b-th child (element) in each group of a child elements of its parent element.
  • :nth-child(-an+b) — Match the element if it is the first child (element) in each group of a child elements, up to the first b child elements of its parent element.
  • :nth-child(odd) — Match element in the odd position (i.e. first, third). Same as :nth-child(2n+1).
  • :nth-child(even) — Match element in the even position (i.e. second, fourth). Same as :nth-child(2n+2).
  • :nth-of-type(..) — As above, but only counts elements of its type.
  • :nth-last-child(..) — As above, but counts from the last child.
  • :nth-last-of-type(..) — As above, but counts from the last child and only elements of its type.
  • :not(selector) — Match the element only if the element does not match the simple selector.

As you can see, <tt>:nth-child<tt> pseudo class and its varient can get quite tricky and the CSS specification doesn‘t do a much better job explaining it. But after reading the examples and trying a few combinations, it‘s easy to figure out.

For example:

  table tr:nth-child(odd)

Selects every second row in the table starting with the first one.

  div p:nth-child(4)

Selects the fourth paragraph in the div, but not if the div contains other elements, since those are also counted.

  div p:nth-of-type(4)

Selects the fourth paragraph in the div, counting only paragraphs, and ignoring all other elements.

  div p:nth-of-type(-n+4)

Selects the first four paragraphs, ignoring all others.

And you can always select an element that matches one set of rules but not another using :not. For example:

  p:not(.post)

Matches all paragraphs that do not have the class .post.

Substitution Values

You can use substitution with identifiers, class names and element values. A substitution takes the form of a question mark (?) and uses the next value in the argument list following the CSS expression.

The substitution value may be a string or a regular expression. All other values are converted to strings.

For example:

  selector = HTML::Selector.new "#?", /^\d+$/

matches any element whose identifier consists of one or more digits.

See www.w3.org/TR/css3-selectors/

Methods
  • attribute_match
  • for_class
  • for_id
  • match
  • new
  • next_element
  • next_selector
  • nth_child
  • only_child
  • select
  • select_first
  • simple_selector
Public Class methods
Selector.for_class(cls) => selector

Creates a new selector for the given class name.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 214
214:       def for_class(cls)
215:         self.new([".?", cls])
216:       end
Selector.for_id(id) => selector

Creates a new selector for the given id.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 223
223:       def for_id(id)
224:         self.new(["#?", id])
225:       end
Selector.new(string, [values ...]) => selector

Creates a new selector from a CSS 2 selector expression.

The first argument is the selector expression. All other arguments are used for value substitution.

Throws InvalidSelectorError is the selector expression is invalid.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 239
239:     def initialize(selector, *values)
240:       raise ArgumentError, "CSS expression cannot be empty" if selector.empty?
241:       @source = ""
242:       values = values[0] if values.size == 1 && values[0].is_a?(Array)
243:
244:       # We need a copy to determine if we failed to parse, and also
245:       # preserve the original pass by-ref statement.
246:       statement = selector.strip.dup
247:
248:       # Create a simple selector, along with negation.
249:       simple_selector(statement, values).each { |name, value| instance_variable_set("@#{name}", value) }
250:
251:       @alternates = []
252:       @depends = nil
253:
254:       # Alternative selector.
255:       if statement.sub!(/^\s*,\s*/, "")
256:         second = Selector.new(statement, values)
257:         @alternates << second
258:         # If there are alternate selectors, we group them in the top selector.
259:         if alternates = second.instance_variable_get(:@alternates)
260:           second.instance_variable_set(:@alternates, [])
261:           @alternates.concat alternates
262:         end
263:         @source << " , " << second.to_s
264:       # Sibling selector: create a dependency into second selector that will
265:       # match element immediately following this one.
266:       elsif statement.sub!(/^\s*\+\s*/, "")
267:         second = next_selector(statement, values)
268:         @depends = lambda do |element, first|
269:           if element = next_element(element)
270:             second.match(element, first)
271:           end
272:         end
273:         @source << " + " << second.to_s
274:       # Adjacent selector: create a dependency into second selector that will
275:       # match all elements following this one.
276:       elsif statement.sub!(/^\s*~\s*/, "")
277:         second = next_selector(statement, values)
278:         @depends = lambda do |element, first|
279:           matches = []
280:           while element = next_element(element)
281:             if subset = second.match(element, first)
282:               if first && !subset.empty?
283:                 matches << subset.first
284:                 break
285:               else
286:                 matches.concat subset
287:               end
288:             end
289:           end
290:           matches.empty? ? nil : matches
291:         end
292:         @source << " ~ " << second.to_s
293:       # Child selector: create a dependency into second selector that will
294:       # match a child element of this one.
295:       elsif statement.sub!(/^\s*>\s*/, "")
296:         second = next_selector(statement, values)
297:         @depends = lambda do |element, first|
298:           matches = []
299:           element.children.each do |child|
300:             if child.tag? && subset = second.match(child, first)
301:               if first && !subset.empty?
302:                 matches << subset.first
303:                 break
304:               else
305:                 matches.concat subset
306:               end
307:             end
308:           end
309:           matches.empty? ? nil : matches
310:         end
311:         @source << " > " << second.to_s
312:       # Descendant selector: create a dependency into second selector that
313:       # will match all descendant elements of this one. Note,
314:       elsif statement =~ /^\s+\S+/ && statement != selector
315:         second = next_selector(statement, values)
316:         @depends = lambda do |element, first|
317:           matches = []
318:           stack = element.children.reverse
319:           while node = stack.pop
320:             next unless node.tag?
321:             if subset = second.match(node, first)
322:               if first && !subset.empty?
323:                 matches << subset.first
324:                 break
325:               else
326:                 matches.concat subset
327:               end
328:             elsif children = node.children
329:               stack.concat children.reverse
330:             end
331:           end
332:           matches.empty? ? nil : matches
333:         end
334:         @source << " " << second.to_s
335:       else
336:         # The last selector is where we check that we parsed
337:         # all the parts.
338:         unless statement.empty? || statement.strip.empty?
339:           raise ArgumentError, "Invalid selector: #{statement}"
340:         end
341:       end
342:     end
Public Instance methods
match(element, first?) => array or nil

Matches an element against the selector.

For a simple selector this method returns an array with the element if the element matches, nil otherwise.

For a complex selector (sibling and descendant) this method returns an array with all matching elements, nil if no match is found.

Use +first_only=true+ if you are only interested in the first element.

For example:

  if selector.match(element)
    puts "Element is a login form"
  end

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 363
363:     def match(element, first_only = false)
364:       # Match element if no element name or element name same as element name
365:       if matched = (!@tag_name || @tag_name == element.name)
366:         # No match if one of the attribute matches failed
367:         for attr in @attributes
368:           if element.attributes[attr[0]] !~ attr[1]
369:             matched = false
370:             break
371:           end
372:         end
373:       end
374:
375:       # Pseudo class matches (nth-child, empty, etc).
376:       if matched
377:         for pseudo in @pseudo
378:           unless pseudo.call(element)
379:             matched = false
380:             break
381:           end
382:         end
383:       end
384:
385:       # Negation. Same rules as above, but we fail if a match is made.
386:       if matched && @negation
387:         for negation in @negation
388:           if negation[:tag_name] == element.name
389:             matched = false
390:           else
391:             for attr in negation[:attributes]
392:               if element.attributes[attr[0]] =~ attr[1]
393:                 matched = false
394:                 break
395:               end
396:             end
397:           end
398:           if matched
399:             for pseudo in negation[:pseudo]
400:               if pseudo.call(element)
401:                 matched = false
402:                 break
403:               end
404:             end
405:           end
406:           break unless matched
407:         end
408:       end
409:
410:       # If element matched but depends on another element (child,
411:       # sibling, etc), apply the dependent matches instead.
412:       if matched && @depends
413:         matches = @depends.call(element, first_only)
414:       else
415:         matches = matched ? [element] : nil
416:       end
417:
418:       # If this selector is part of the group, try all the alternative
419:       # selectors (unless first_only).
420:       if !first_only || !matches
421:         @alternates.each do |alternate|
422:           break if matches && first_only
423:           if subset = alternate.match(element, first_only)
424:             if matches
425:               matches.concat subset
426:             else
427:               matches = subset
428:             end
429:           end
430:         end
431:       end
432:
433:       matches
434:     end
next_element(element, name = nil)

Return the next element after this one. Skips sibling text nodes.

With the name argument, returns the next element with that name, skipping other sibling elements.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 493
493:     def next_element(element, name = nil)
494:       if siblings = element.parent.children
495:         found = false
496:         siblings.each do |node|
497:           if node.equal?(element)
498:             found = true
499:           elsif found && node.tag?
500:             return node if (name.nil? || node.name == name)
501:           end
502:         end
503:       end
504:       nil
505:     end
select(root) => array

Selects and returns an array with all matching elements, beginning with one node and traversing through all children depth-first. Returns an empty array if no match is found.

The root node may be any element in the document, or the document itself.

For example:

  selector = HTML::Selector.new "input[type=text]"
  matches = selector.select(element)
  matches.each do |match|
    puts "Found text field with name #{match.attributes['name']}"
  end

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 453
453:     def select(root)
454:       matches = []
455:       stack = [root]
456:       while node = stack.pop
457:         if node.tag? && subset = match(node, false)
458:           subset.each do |match|
459:             matches << match unless matches.any? { |item| item.equal?(match) }
460:           end
461:         elsif children = node.children
462:           stack.concat children.reverse
463:         end
464:       end
465:       matches
466:     end
select_first(root)

Similar to select but returns the first matching element. Returns nil if no element matches the selector.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 471
471:     def select_first(root)
472:       stack = [root]
473:       while node = stack.pop
474:         if node.tag? && subset = match(node, true)
475:           return subset.first if !subset.empty?
476:         elsif children = node.children
477:           stack.concat children.reverse
478:         end
479:       end
480:       nil
481:     end
Protected Instance methods
attribute_match(equality, value)

Create a regular expression to match an attribute value based on the equality operator (=, ^=, |=, etc).

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 687
687:     def attribute_match(equality, value)
688:       regexp = value.is_a?(Regexp) ? value : Regexp.escape(value.to_s)
689:       case equality
690:         when "=" then
691:           # Match the attribute value in full
692:           Regexp.new("^#{regexp}$")
693:         when "~=" then
694:           # Match a space-separated word within the attribute value
695:           Regexp.new("(^|\s)#{regexp}($|\s)")
696:         when "^="
697:           # Match the beginning of the attribute value
698:           Regexp.new("^#{regexp}")
699:         when "$="
700:           # Match the end of the attribute value
701:           Regexp.new("#{regexp}$")
702:         when "*="
703:           # Match substring of the attribute value
704:           regexp.is_a?(Regexp) ? regexp : Regexp.new(regexp)
705:         when "|=" then
706:           # Match the first space-separated item of the attribute value
707:           Regexp.new("^#{regexp}($|\s)")
708:         else
709:           raise InvalidSelectorError, "Invalid operation/value" unless value.empty?
710:           # Match all attributes values (existence check)
711:           //
712:       end
713:     end
next_selector(statement, values)

Called to create a dependent selector (sibling, descendant, etc). Passes the remainder of the statement that will be reduced to zero eventually, and array of substitution values.

This method is called from four places, so it helps to put it here for reuse. The only logic deals with the need to detect comma separators (alternate) and apply them to the selector group of the top selector.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 800
800:     def next_selector(statement, values)
801:       second = Selector.new(statement, values)
802:       # If there are alternate selectors, we group them in the top selector.
803:       if alternates = second.instance_variable_get(:@alternates)
804:         second.instance_variable_set(:@alternates, [])
805:         @alternates.concat alternates
806:       end
807:       second
808:     end
nth_child(a, b, of_type, reverse)

Returns a lambda that can match an element against the nth-child pseudo class, given the following arguments:

  • a — Value of a part.
  • b — Value of b part.
  • of_type — True to test only elements of this type (of-type).
  • reverse — True to count in reverse order (last-).

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 722
722:     def nth_child(a, b, of_type, reverse)
723:       # a = 0 means select at index b, if b = 0 nothing selected
724:       return lambda { |element| false } if a == 0 && b == 0
725:       # a < 0 and b < 0 will never match against an index
726:       return lambda { |element| false } if a < 0 && b < 0
727:       b = a + b + 1 if b < 0   # b < 0 just picks last element from each group
728:       b -= 1 unless b == 0  # b == 0 is same as b == 1, otherwise zero based
729:       lambda do |element|
730:         # Element must be inside parent element.
731:         return false unless element.parent && element.parent.tag?
732:         index = 0
733:         # Get siblings, reverse if counting from last.
734:         siblings = element.parent.children
735:         siblings = siblings.reverse if reverse
736:         # Match element name if of-type, otherwise ignore name.
737:         name = of_type ? element.name : nil
738:         found = false
739:         for child in siblings
740:           # Skip text nodes/comments.
741:           if child.tag? && (name == nil || child.name == name)
742:             if a == 0
743:               # Shortcut when a == 0 no need to go past count
744:               if index == b
745:                 found = child.equal?(element)
746:                 break
747:               end
748:             elsif a < 0
749:               # Only look for first b elements
750:               break if index > b
751:               if child.equal?(element)
752:                 found = (index % a) == 0
753:                 break
754:               end
755:             else
756:               # Otherwise, break if child found and count ==  an+b
757:               if child.equal?(element)
758:                 found = (index % a) == b
759:                 break
760:               end
761:             end
762:             index += 1
763:           end
764:         end
765:         found
766:       end
767:     end
only_child(of_type)

Creates a only child lambda. Pass +of-type+ to only look at elements of its type.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 772
772:     def only_child(of_type)
773:       lambda do |element|
774:         # Element must be inside parent element.
775:         return false unless element.parent && element.parent.tag?
776:         name = of_type ? element.name : nil
777:         other = false
778:         for child in element.parent.children
779:           # Skip text nodes/comments.
780:           if child.tag? && (name == nil || child.name == name)
781:             unless child.equal?(element)
782:               other = true
783:               break
784:             end
785:           end
786:         end
787:         !other
788:       end
789:     end
simple_selector(statement, values, can_negate = true)

Creates a simple selector given the statement and array of substitution values.

Returns a hash with the values tag_name, attributes, pseudo (classes) and negation.

Called the first time with can_negate true to allow negation. Called a second time with false since negation cannot be negated.

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 520
520:     def simple_selector(statement, values, can_negate = true)
521:       tag_name = nil
522:       attributes = []
523:       pseudo = []
524:       negation = []
525:
526:       # Element name. (Note that in negation, this can come at
527:       # any order, but for simplicity we allow if only first).
528:       statement.sub!(/^(\*|[[:alpha:]][\w\-]*)/) do |match|
529:         match.strip!
530:         tag_name = match.downcase unless match == "*"
531:         @source << match
532:         "" # Remove
533:       end
534:
535:       # Get identifier, class, attribute name, pseudo or negation.
536:       while true
537:         # Element identifier.
538:         next if statement.sub!(/^#(\?|[\w\-]+)/) do |match|
539:           id = $1
540:           if id == "?"
541:             id = values.shift
542:           end
543:           @source << "##{id}"
544:           id = Regexp.new("^#{Regexp.escape(id.to_s)}$") unless id.is_a?(Regexp)
545:           attributes << ["id", id]
546:           "" # Remove
547:         end
548:
549:         # Class name.
550:         next if statement.sub!(/^\.([\w\-]+)/) do |match|
551:           class_name = $1
552:           @source << ".#{class_name}"
553:           class_name = Regexp.new("(^|\s)#{Regexp.escape(class_name)}($|\s)") unless class_name.is_a?(Regexp)
554:           attributes << ["class", class_name]
555:           "" # Remove
556:         end
557:
558:         # Attribute value.
559:         next if statement.sub!(/^\[\s*([[:alpha:]][\w\-]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match|
560:           name, equality, value = $1, $2, $3
561:           if value == "?"
562:             value = values.shift
563:           else
564:             # Handle single and double quotes.
565:             value.strip!
566:             if (value[0] == ?" || value[0] == ?') && value[0] == value[-1]
567:               value = value[1..-2]
568:             end
569:           end
570:           @source << "[#{name}#{equality}'#{value}']"
571:           attributes << [name.downcase.strip, attribute_match(equality, value)]
572:           "" # Remove
573:         end
574:
575:         # Root element only.
576:         next if statement.sub!(/^:root/) do |match|
577:           pseudo << lambda do |element|
578:             element.parent.nil? || !element.parent.tag?
579:           end
580:           @source << ":root"
581:           "" # Remove
582:         end
583:
584:         # Nth-child including last and of-type.
585:         next if statement.sub!(/^:nth-(last-)?(child|of-type)\((odd|even|(\d+|\?)|(-?\d*|\?)?n([+\-]\d+|\?)?)\)/) do |match|
586:           reverse = $1 == "last-"
587:           of_type = $2 == "of-type"
588:           @source << ":nth-#{$1}#{$2}("
589:           case $3
590:             when "odd"
591:               pseudo << nth_child(2, 1, of_type, reverse)
592:               @source << "odd)"
593:             when "even"
594:               pseudo << nth_child(2, 2, of_type, reverse)
595:               @source << "even)"
596:             when /^(\d+|\?)$/  # b only
597:               b = ($1 == "?" ? values.shift : $1).to_i
598:               pseudo << nth_child(0, b, of_type, reverse)
599:               @source << "#{b})"
600:             when /^(-?\d*|\?)?n([+\-]\d+|\?)?$/
601:               a = ($1 == "?" ? values.shift :
602:                    $1 == "" ? 1 : $1 == "-" ? -1 : $1).to_i
603:               b = ($2 == "?" ? values.shift : $2).to_i
604:               pseudo << nth_child(a, b, of_type, reverse)
605:               @source << (b >= 0 ? "#{a}n+#{b})" : "#{a}n#{b})")
606:             else
607:               raise ArgumentError, "Invalid nth-child #{match}"
608:           end
609:           "" # Remove
610:         end
611:         # First/last child (of type).
612:         next if statement.sub!(/^:(first|last)-(child|of-type)/) do |match|
613:           reverse = $1 == "last"
614:           of_type = $2 == "of-type"
615:           pseudo << nth_child(0, 1, of_type, reverse)
616:           @source << ":#{$1}-#{$2}"
617:           "" # Remove
618:         end
619:         # Only child (of type).
620:         next if statement.sub!(/^:only-(child|of-type)/) do |match|
621:           of_type = $1 == "of-type"
622:           pseudo << only_child(of_type)
623:           @source << ":only-#{$1}"
624:           "" # Remove
625:         end
626:
627:         # Empty: no child elements or meaningful content (whitespaces
628:         # are ignored).
629:         next if statement.sub!(/^:empty/) do |match|
630:           pseudo << lambda do |element|
631:             empty = true
632:             for child in element.children
633:               if child.tag? || !child.content.strip.empty?
634:                 empty = false
635:                 break
636:               end
637:             end
638:             empty
639:           end
640:           @source << ":empty"
641:           "" # Remove
642:         end
643:         # Content: match the text content of the element, stripping
644:         # leading and trailing spaces.
645:         next if statement.sub!(/^:content\(\s*(\?|'[^']*'|"[^"]*"|[^)]*)\s*\)/) do |match|
646:           content = $1
647:           if content == "?"
648:             content = values.shift
649:           elsif (content[0] == ?" || content[0] == ?') && content[0] == content[-1]
650:             content = content[1..-2]
651:           end
652:           @source << ":content('#{content}')"
653:           content = Regexp.new("^#{Regexp.escape(content.to_s)}$") unless content.is_a?(Regexp)
654:           pseudo << lambda do |element|
655:             text = ""
656:             for child in element.children
657:               unless child.tag?
658:                 text << child.content
659:               end
660:             end
661:             text.strip =~ content
662:           end
663:           "" # Remove
664:         end
665:
666:         # Negation. Create another simple selector to handle it.
667:         if statement.sub!(/^:not\(\s*/, "")
668:           raise ArgumentError, "Double negatives are not missing feature" unless can_negate
669:           @source << ":not("
670:           negation << simple_selector(statement, values, false)
671:           raise ArgumentError, "Negation not closed" unless statement.sub!(/^\s*\)/, "")
672:           @source << ")"
673:           next
674:         end
675:
676:         # No match: moving on.
677:         break
678:       end
679:
680:       # Return hash. The keys are mapped to instance variables.
681:       {:tag_name=>tag_name, :attributes=>attributes, :pseudo=>pseudo, :negation=>negation}
682:     end


Class: HTML::WhiteListSanitizer

Class
HTML::WhiteListSanitizer
In: | actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
Parent: | Sanitizer
Methods
  • contains_bad_protocols?
  • process_attributes_for
  • process_node
  • sanitize_css
  • tokenize
Public Instance methods
sanitize_css(style)

Sanitizes a block of css code. Used by sanitize when it comes across a style attribute

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 104
104:     def sanitize_css(style)
105:       # disallow urls
106:       style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')
107:
108:       # gauntlet
109:       if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ ||
110:           style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$))*$/
111:         return ''
112:       end
113:
114:       clean = []
115:       style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val|
116:         if allowed_css_properties.include?(prop.downcase)
117:           clean <<  prop + ': ' + val + ';'
118:         elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
119:           unless val.split().any? do |keyword|
120:             !allowed_css_keywords.include?(keyword) &&
121:               keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/
122:           end
123:             clean << prop + ': ' + val + ';'
124:           end
125:         end
126:       end
127:       clean.join(' ')
128:     end
Protected Instance methods
contains_bad_protocols?(attr_name, value)

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 168
168:     def contains_bad_protocols?(attr_name, value)
169:       uri_attributes.include?(attr_name) &&
170:       (value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(%|&#37;)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
171:     end
process_attributes_for(node, options)

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 155
155:     def process_attributes_for(node, options)
156:       return unless node.attributes
157:       node.attributes.keys.each do |attr_name|
158:         value = node.attributes[attr_name].to_s
159:
160:         if !options[:attributes].include?(attr_name) || contains_bad_protocols?(attr_name, value)
161:           node.attributes.delete(attr_name)
162:         else
163:           node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(value)
164:         end
165:       end
166:     end
process_node(node, result, options)

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 138
138:     def process_node(node, result, options)
139:       result << case node
140:         when HTML::Tag
141:           if node.closing == :close
142:             options[:parent].shift
143:           else
144:             options[:parent].unshift node.name
145:           end
146:
147:           process_attributes_for node, options
148:
149:           options[:tags].include?(node.name) ? node : nil
150:         else
151:           bad_tags.include?(options[:parent].first) ? nil : node.to_s.gsub(/</, "&lt;")
152:       end
153:     end
tokenize(text, options)

[ show source ]

     # File actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb, line 131
131:     def tokenize(text, options)
132:       options[:parent] = []
133:       options[:attributes] ||= allowed_attributes
134:       options[:tags]       ||= allowed_tags
135:       super
136:     end


Class: HashWithIndifferentAccess

Class
HashWithIndifferentAccess
In: | activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
Parent: | Hash

This class has dubious semantics and we only have it so that people can write params[:key] instead of params[‘key’]

Methods
  • []=
  • convert_key
  • convert_value
  • default
  • delete
  • dup
  • fetch
  • key?
  • merge
  • new
  • stringify_keys!
  • symbolize_keys!
  • to_hash
  • to_options!
  • update
  • values_at
Public Class methods
new(constructor = {})

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 5
 5:   def initialize(constructor = {})
 6:     if constructor.is_a?(Hash)
 7:       super()
 8:       update(constructor)
 9:     else
10:       super(constructor)
11:     end
12:   end
Public Instance methods
[]=(key, value)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 25
25:   def []=(key, value)
26:     regular_writer(convert_key(key), convert_value(value))
27:   end
convert_key(key)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 74
74:     def convert_key(key)
75:       key.kind_of?(Symbol) ? key.to_s : key
76:     end
convert_value(value)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 78
78:     def convert_value(value)
79:       case value
80:       when Hash
81:         value.with_indifferent_access
82:       when Array
83:         value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
84:       else
85:         value
86:       end
87:     end
default(key = nil)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 14
14:   def default(key = nil)
15:     if key.is_a?(Symbol) && include?(key = key.to_s)
16:       self[key]
17:     else
18:       super
19:     end
20:   end
delete(key)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 60
60:   def delete(key)
61:     super(convert_key(key))
62:   end
dup()

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 52
52:   def dup
53:     HashWithIndifferentAccess.new(self)
54:   end
fetch(key, *extras)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 44
44:   def fetch(key, *extras)
45:     super(convert_key(key), *extras)
46:   end
key?(key)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 36
36:   def key?(key)
37:     super(convert_key(key))
38:   end
merge(hash)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 56
56:   def merge(hash)
57:     self.dup.update(hash)
58:   end
stringify_keys!()

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 64
64:   def stringify_keys!; self end
symbolize_keys!()

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 65
65:   def symbolize_keys!; self end
to_hash()

Convert to a Hash with String keys.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 69
69:   def to_hash
70:     Hash.new(default).merge(self)
71:   end
to_options!()

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 66
66:   def to_options!; self end
update(other_hash)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 29
29:   def update(other_hash)
30:     other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
31:     self
32:   end
values_at(*indices)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/indifferent_access.rb, line 48
48:   def values_at(*indices)
49:     indices.collect {|key| self[convert_key(key)]}
50:   end


Module: Inflector

Module
Inflector
In: activesupport/lib/active_support/inflector.rb

The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without, and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept in inflections.rb.

Methods
  • camelize
  • classify
  • constantize
  • dasherize
  • demodulize
  • foreign_key
  • humanize
  • inflections
  • ordinalize
  • pluralize
  • singularize
  • tableize
  • titleize
  • underscore
Classes and Modules
Class Inflector::Inflections
Public Instance methods
camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)

By default, camelize converts strings to UpperCamelCase. If the argument to camelize is set to ":lower" then camelize produces lowerCamelCase.

camelize will also convert ’/’ to ’::’ which is useful for converting paths to namespaces

Examples

  "active_record".camelize #=> "ActiveRecord"
  "active_record".camelize(:lower) #=> "activeRecord"
  "active_record/errors".camelize #=> "ActiveRecord::Errors"
  "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 147
147:   def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
148:     if first_letter_in_uppercase
149:       lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
150:     else
151:       lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
152:     end
153:   end
classify(table_name)

Create a class name from a table name like Rails does for table names to models. Note that this returns a string and not a Class. (To convert to an actual class follow classify with constantize.)

Examples

  "egg_and_hams".classify #=> "EggAndHam"
  "post".classify #=> "Post"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 228
228:   def classify(table_name)
229:     # strip out any leading schema name
230:     camelize(singularize(table_name.to_s.sub(/.*\./, '')))
231:   end
constantize(camel_cased_word)

Constantize tries to find a declared constant with the name specified in the string. It raises a NameError when the name is not in CamelCase or is not initialized.

Examples

  "Module".constantize #=> Module
  "Class".constantize #=> Class

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 252
252:   def constantize(camel_cased_word)
253:     unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
254:       raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
255:     end
256:
257:     Object.module_eval("::#{$1}", __FILE__, __LINE__)
258:   end
dasherize(underscored_word)

Replaces underscores with dashes in the string.

Example

  "puni_puni" #=> "puni-puni"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 187
187:   def dasherize(underscored_word)
188:     underscored_word.gsub(/_/, '-')
189:   end
demodulize(class_name_in_module)

Removes the module part from the expression in the string

Examples

  "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
  "Inflections".demodulize #=> "Inflections"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 206
206:   def demodulize(class_name_in_module)
207:     class_name_in_module.to_s.gsub(/^.*::/, '')
208:   end
foreign_key(class_name, separate_class_name_and_id_with_underscore = true)

Creates a foreign key name from a class name. separate_class_name_and_id_with_underscore sets whether the method should put ‘_’ between the name and ‘id’.

Examples

  "Message".foreign_key #=> "message_id"
  "Message".foreign_key(false) #=> "messageid"
  "Admin::Post".foreign_key #=> "post_id"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 241
241:   def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
242:     underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
243:   end
humanize(lower_case_and_underscored_word)

Capitalizes the first word and turns underscores into spaces and strips _id. Like titleize, this is meant for creating pretty output.

Examples

  "employee_salary" #=> "Employee salary"
  "author_id" #=> "Author"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 197
197:   def humanize(lower_case_and_underscored_word)
198:     lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
199:   end
inflections() {|Inflections.instance| ...}

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 89
89:   def inflections
90:     if block_given?
91:       yield Inflections.instance
92:     else
93:       Inflections.instance
94:     end
95:   end
ordinalize(number)

Ordinalize turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th.

Examples

  ordinalize(1)     # => "1st"
  ordinalize(2)     # => "2nd"
  ordinalize(1002)  # => "1002nd"
  ordinalize(1003)  # => "1003rd"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 268
268:   def ordinalize(number)
269:     if (11..13).include?(number.to_i % 100)
270:       "#{number}th"
271:     else
272:       case number.to_i % 10
273:         when 1; "#{number}st"
274:         when 2; "#{number}nd"
275:         when 3; "#{number}rd"
276:         else    "#{number}th"
277:       end
278:     end
279:   end
pluralize(word)

Returns the plural form of the word in the string.

Examples

  "post".pluralize #=> "posts"
  "octopus".pluralize #=> "octopi"
  "sheep".pluralize #=> "sheep"
  "words".pluralize #=> "words"
  "the blue mailman".pluralize #=> "the blue mailmen"
  "CamelOctopus".pluralize #=> "CamelOctopi"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 106
106:   def pluralize(word)
107:     result = word.to_s.dup
108:
109:     if word.empty? || inflections.uncountables.include?(result.downcase)
110:       result
111:     else
112:       inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
113:       result
114:     end
115:   end
singularize(word)

The reverse of pluralize, returns the singular form of a word in a string.

Examples

  "posts".singularize #=> "post"
  "octopi".singularize #=> "octopus"
  "sheep".singluarize #=> "sheep"
  "word".singluarize #=> "word"
  "the blue mailmen".singularize #=> "the blue mailman"
  "CamelOctopi".singularize #=> "CamelOctopus"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 126
126:   def singularize(word)
127:     result = word.to_s.dup
128:
129:     if inflections.uncountables.include?(result.downcase)
130:       result
131:     else
132:       inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
133:       result
134:     end
135:   end
tableize(class_name)

Create the name of a table like Rails does for models to table names. This method uses the pluralize method on the last word in the string.

Examples

  "RawScaledScorer".tableize #=> "raw_scaled_scorers"
  "egg_and_ham".tableize #=> "egg_and_hams"
  "fancyCategory".tableize #=> "fancy_categories"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 217
217:   def tableize(class_name)
218:     pluralize(underscore(class_name))
219:   end
titleize(word)

Capitalizes all the words and replaces some characters in the string to create a nicer looking title. Titleize is meant for creating pretty output. It is not used in the Rails internals.

titleize is also aliased as as titlecase

Examples

  "man from the boondocks".titleize #=> "Man From The Boondocks"
  "x-men: the last stand".titleize #=> "X Men: The Last Stand"

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 164
164:   def titleize(word)
165:     humanize(underscore(word)).gsub(/\b([a-z])/) { $1.capitalize }
166:   end
underscore(camel_cased_word)

The reverse of camelize. Makes an underscored form from the expression in the string.

Changes ’::’ to ’/’ to convert namespaces to paths.

Examples

  "ActiveRecord".underscore #=> "active_record"
  "ActiveRecord::Errors".underscore #=> active_record/errors

[ show source ]

     # File activesupport/lib/active_support/inflector.rb, line 175
175:   def underscore(camel_cased_word)
176:     camel_cased_word.to_s.gsub(/::/, '/').
177:       gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
178:       gsub(/([a-z\d])([A-Z])/,'\1_\2').
179:       tr("-", "_").
180:       downcase
181:   end


Class: Inflector::Inflections

Class
Inflector::Inflections
In: | activesupport/lib/active_support/inflector.rb
Parent: | Object

A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional inflection rules. Examples:

  Inflector.inflections do |inflect|
    inflect.plural /^(ox)$/i, '\1\2en'
    inflect.singular /^(ox)en/i, '\1'

    inflect.irregular 'octopus', 'octopi'

    inflect.uncountable "equipment"
  end

New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may already have been loaded.

Methods
  • clear
  • irregular
  • new
  • plural
  • singular
  • uncountable
Included Modules
  • Singleton
Attributes
[R] | plurals
[R] | singulars
[R] | uncountables
Public Class methods
new()

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 27
27:     def initialize
28:       @plurals, @singulars, @uncountables = [], [], []
29:     end
Public Instance methods
clear(scope = :all)

Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type, the options are: :plurals, :singulars, :uncountables

Examples:

  clear :all
  clear :plurals

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 77
77:     def clear(scope = :all)
78:       case scope
79:         when :all
80:           @plurals, @singulars, @uncountables = [], [], []
81:         else
82:           instance_variable_set "@#{scope}", []
83:       end
84:     end
irregular(singular, plural)

Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used for strings, not regular expressions. You simply pass the irregular in singular and plural form.

Examples:

  irregular 'octopus', 'octopi'
  irregular 'person', 'people'

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 49
49:     def irregular(singular, plural)
50:       if singular[0,1].upcase == plural[0,1].upcase
51:         plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
52:         singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
53:       else
54:         plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
55:         plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
56:         singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
57:         singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
58:       end
59:     end
plural(rule, replacement)

Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression. The replacement should always be a string that may include references to the matched data from the rule.

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 33
33:     def plural(rule, replacement)
34:       @plurals.insert(0, [rule, replacement])
35:     end
singular(rule, replacement)

Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression. The replacement should always be a string that may include references to the matched data from the rule.

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 39
39:     def singular(rule, replacement)
40:       @singulars.insert(0, [rule, replacement])
41:     end
uncountable(*words)

Add uncountable words that shouldn‘t be attempted inflected.

Examples:

  uncountable "money"
  uncountable "money", "information"
  uncountable %w( money information rice )

[ show source ]

    # File activesupport/lib/active_support/inflector.rb, line 67
67:     def uncountable(*words)
68:       (@uncountables << words).flatten!
69:     end


Module: Kernel

Module
Kernel
In: activesupport/lib/active_support/core_ext/kernel/daemonizing.rb activesupport/lib/active_support/core_ext/kernel/debugger.rb activesupport/lib/active_support/core_ext/kernel/reporting.rb activesupport/lib/active_support/core_ext/kernel/requires.rb activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb

Since Ruby is very dynamic, methods added to the ancestors of BlankSlate after BlankSlate is defined will show up in the list of available BlankSlate methods. We handle this by defining a hook in the Object and Kernel classes that will hide any method defined after BlankSlate has been loaded.

Methods
  • breakpoint
  • daemonize
  • debugger
  • enable_warnings
  • method_added
  • require_library_or_gem
  • silence_stream
  • silence_warnings
  • suppress
Public Class methods
method_added(name)

Detect method additions to Kernel and remove them in the BlankSlate class.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 65
65:     def method_added(name)
66:       result = blank_slate_method_added(name)
67:       return result if self != Kernel
68:       BlankSlate.hide(name)
69:       result
70:     end
Public Instance methods
breakpoint()

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/debugger.rb, line 9
 9:   def breakpoint
10:     RAILS_DEFAULT_LOGGER.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n"
11:     debugger
12:   end
daemonize()

Turns the current script into a daemon process that detaches from the console. It can be shut down with a TERM signal.

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/daemonizing.rb, line 4
 4:   def daemonize
 5:     exit if fork                   # Parent exits, child continues.
 6:     Process.setsid                 # Become session leader.
 7:     exit if fork                   # Zap session leader. See [1].
 8:     Dir.chdir "/"                  # Release old working directory.
 9:     File.umask 0000                # Ensure sensible umask. Adjust as needed.
10:     STDIN.reopen "/dev/null"       # Free file descriptors and
11:     STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
12:     STDERR.reopen STDOUT           # STDOUT/ERR should better go to a logfile.
13:     trap("TERM") { exit }
14:   end
debugger()

Starts a debugging session if ruby-debug has been loaded (call script/server —debugger to do load it).

[ show source ]

   # File activesupport/lib/active_support/core_ext/kernel/debugger.rb, line 4
4:     def debugger
5:       RAILS_DEFAULT_LOGGER.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
6:     end
enable_warnings() {|| ...}

Sets $VERBOSE to true for the duration of the block and back to its original value afterwards.

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/reporting.rb, line 17
17:   def enable_warnings
18:     old_verbose, $VERBOSE = $VERBOSE, true
19:     yield
20:   ensure
21:     $VERBOSE = old_verbose
22:   end
require_library_or_gem(library_name)

Require a library with fallback to RubyGems. Warnings during library loading are silenced to increase signal/noise for application warnings.

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/requires.rb, line 4
 4:   def require_library_or_gem(library_name)
 5:     silence_warnings do
 6:       begin
 7:         require library_name
 8:       rescue LoadError => cannot_require
 9:         # 1. Requiring the module is unsuccessful, maybe it's a gem and nobody required rubygems yet. Try.
10:         begin
11:           require 'rubygems'
12:         rescue LoadError => rubygems_not_installed
13:           raise cannot_require
14:         end
15:         # 2. Rubygems is installed and loaded. Try to load the library again
16:         begin
17:           require library_name
18:         rescue LoadError => gem_not_installed
19:           raise cannot_require
20:         end
21:       end
22:     end
23:   end
silence_stream(stream) {|| ...}

Silences any stream for the duration of the block.

  silence_stream(STDOUT) do
    puts 'This will never be seen'
  end

  puts 'But this will'

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/reporting.rb, line 36
36:   def silence_stream(stream)
37:     old_stream = stream.dup
38:     stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
39:     stream.sync = true
40:     yield
41:   ensure
42:     stream.reopen(old_stream)
43:   end
silence_warnings() {|| ...}

Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.

  silence_warnings do
    value = noisy_call # no warning voiced
  end

  noisy_call # warning voiced

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/reporting.rb, line 9
 9:   def silence_warnings
10:     old_verbose, $VERBOSE = $VERBOSE, nil
11:     yield
12:   ensure
13:     $VERBOSE = old_verbose
14:   end
suppress(*exception_classes) {|| ...}

[ show source ]

    # File activesupport/lib/active_support/core_ext/kernel/reporting.rb, line 45
45:   def suppress(*exception_classes)
46:     begin yield
47:     rescue Exception => e
48:       raise unless exception_classes.any? { |cls| e.kind_of?(cls) }
49:     end
50:   end


Class: Logger

Class
Logger
In: | activesupport/lib/active_support/clean_logger.rb activesupport/lib/active_support/core_ext/logger.rb
Parent: | Object

Adds the ‘around_level’ method to Logger.

Methods
  • datetime_format
  • datetime_format=
  • define_around_helper
  • formatter
  • silence
Classes and Modules
Class Logger::Formatter
Class Logger::SimpleFormatter
Public Class methods
define_around_helper(level)

[ show source ]

   # File activesupport/lib/active_support/core_ext/logger.rb, line 4
4:   def self.define_around_helper(level)
5:     module_eval "def around_\#{level}(before_message, after_message, &block)\nself.\#{level}(before_message)\nreturn_value = block.call(self)\nself.\#{level}(after_message)\nreturn return_value\nend\n"
6:   end
Public Instance methods
datetime_format()

Get the logging datetime format. Returns nil if the formatter does not support datetime formatting.

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 45
45:   def datetime_format
46:     formatter.datetime_format if formatter.respond_to?(:datetime_format)
47:   end
datetime_format=(datetime_format)

Logging date-time format (string passed to strftime). Ignored if the formatter does not respond to datetime_format=.

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 38
38:   def datetime_format=(datetime_format)
39:     formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
40:   end
formatter()

Get the current formatter. The default formatter is a SimpleFormatter which only displays the log message

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 52
52:   def formatter
53:     @formatter ||= SimpleFormatter.new
54:   end
silence(temporary_level = Logger::ERROR) {|self| ...}

Silences the logger for the duration of the block.

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 22
22:   def silence(temporary_level = Logger::ERROR)
23:     if silencer
24:       begin
25:         old_logger_level, self.level = level, temporary_level
26:         yield self
27:       ensure
28:         self.level = old_logger_level
29:       end
30:     else
31:       yield self
32:     end
33:   end


Class: Logger::Formatter

Class
Logger::Formatter
In: | activesupport/lib/active_support/clean_logger.rb
Parent: | Object
Methods
  • call
  • new
Constants
Format = "%s, [%s#%d] %5s -- %s: %s\n"
Attributes
[RW] datetime_format
Public Class methods
new()

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 62
62:       def initialize
63:         @datetime_format = nil
64:       end
Public Instance methods
call(severity, time, progname, msg)

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 66
66:       def call(severity, time, progname, msg)
67:         Format % [severity[0..0], format_datetime(time), $$, severity, progname,
68:         msg2str(msg)]
69:       end


Class: Logger::SimpleFormatter

Class
Logger::SimpleFormatter
In: | activesupport/lib/active_support/clean_logger.rb
Parent: | Logger::Formatter

Simple formatter which only displays the message.

Methods
  • call
Public Instance methods
call(severity, timestamp, progname, msg)

This method is invoked when a log event occurs

[ show source ]

    # File activesupport/lib/active_support/clean_logger.rb, line 97
97:     def call(severity, timestamp, progname, msg)
98:       "#{String === msg ? msg : msg.inspect}\n"
99:     end


Module: Mime

Module
Mime
In: actionpack/lib/action_controller/mime_type.rb
Classes and Modules
Class Mime::Type
Constants
SET | = | []
EXTENSION_LOOKUP | = | Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
LOOKUP | = | Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }


Class: Mime::Type

Class
Mime::Type
In: | actionpack/lib/action_controller/mime_type.rb
Parent: | Object

Encapsulates the notion of a mime type. Can be used at render time, for example, with:

  class PostsController < ActionController::Base
    def show
      @post = Post.find(params[:id])

      respond_to do |format|
        format.html
        format.ics { render :text => post.to_ics, :mime_type => Mime::Type["text/calendar"]  }
        format.xml { render :xml => @people.to_xml }
      end
    end
  end
Methods
  • ==
  • ===
  • lookup
  • lookup_by_extension
  • new
  • parse
  • register
  • register_alias
  • to_s
  • to_str
  • to_sym
Public Class methods
lookup(string)

[ show source ]

    # File actionpack/lib/action_controller/mime_type.rb, line 47
47:       def lookup(string)
48:         LOOKUP[string]
49:       end
lookup_by_extension(extension)

[ show source ]

    # File actionpack/lib/action_controller/mime_type.rb, line 51
51:       def lookup_by_extension(extension)
52:         EXTENSION_LOOKUP[extension]
53:       end
new(string, symbol = nil, synonyms = [])

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 122
122:     def initialize(string, symbol = nil, synonyms = [])
123:       @symbol, @synonyms = symbol, synonyms
124:       @string = string
125:     end
parse(accept_header)

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 70
 70:       def parse(accept_header)
 71:         # keep track of creation order to keep the subsequent sort stable
 72:         list = []
 73:         accept_header.split(/,/).each_with_index do |header, index|
 74:           params = header.split(/;\s*q=/)
 75:           list << AcceptItem.new(index, *params) unless params.empty?
 76:         end
 77:         list.sort!
 78:
 79:         # Take care of the broken text/xml entry by renaming or deleting it
 80:         text_xml = list.index("text/xml")
 81:         app_xml = list.index(Mime::XML.to_s)
 82:
 83:         if text_xml && app_xml
 84:           # set the q value to the max of the two
 85:           list[app_xml].q = [list[text_xml].q, list[app_xml].q].max
 86:
 87:           # make sure app_xml is ahead of text_xml in the list
 88:           if app_xml > text_xml
 89:             list[app_xml], list[text_xml] = list[text_xml], list[app_xml]
 90:             app_xml, text_xml = text_xml, app_xml
 91:           end
 92:
 93:           # delete text_xml from the list
 94:           list.delete_at(text_xml)
 95:
 96:         elsif text_xml
 97:           list[text_xml].name = Mime::XML.to_s
 98:         end
 99:
100:         # Look for more specific xml-based types and sort them ahead of app/xml
101:
102:         if app_xml
103:           idx = app_xml
104:           app_xml_type = list[app_xml]
105:
106:           while(idx < list.length)
107:             type = list[idx]
108:             break if type.q < app_xml_type.q
109:             if type.name =~ /\+xml$/
110:               list[app_xml], list[idx] = list[idx], list[app_xml]
111:               app_xml = idx
112:             end
113:             idx += 1
114:           end
115:         end
116:
117:         list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
118:         list
119:       end
register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)

[ show source ]

    # File actionpack/lib/action_controller/mime_type.rb, line 61
61:       def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
62:         Mime.instance_eval { const_set symbol.to_s.upcase, Type.new(string, symbol, mime_type_synonyms) }
63:
64:         SET << Mime.const_get(symbol.to_s.upcase)
65:
66:         ([string] + mime_type_synonyms).each { |string| LOOKUP[string] = SET.last } unless skip_lookup
67:         ([symbol.to_s] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext] = SET.last }
68:       end
register_alias(string, symbol, extension_synonyms = [])

Registers an alias that‘s not used on mime type lookup, but can be referenced directly. Especially useful for rendering different HTML versions depending on the user agent, like an iPhone.

[ show source ]

    # File actionpack/lib/action_controller/mime_type.rb, line 57
57:       def register_alias(string, symbol, extension_synonyms = [])
58:         register(string, symbol, [], extension_synonyms, true)
59:       end
Public Instance methods
==(mime_type)

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 147
147:     def ==(mime_type)
148:       (@synonyms + [ self ]).any? { |synonym| synonym.to_s == mime_type.to_s } if mime_type
149:     end
===(list)

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 139
139:     def ===(list)
140:       if list.is_a?(Array)
141:         (@synonyms + [ self ]).any? { |synonym| list.include?(synonym) }
142:       else
143:         super
144:       end
145:     end
to_s()

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 127
127:     def to_s
128:       @string
129:     end
to_str()

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 131
131:     def to_str
132:       to_s
133:     end
to_sym()

[ show source ]

     # File actionpack/lib/action_controller/mime_type.rb, line 135
135:     def to_sym
136:       @symbol || @string.to_sym
137:     end


Class: Object

Class
Object
In: | actionpack/lib/action_controller/routing.rb activesupport/lib/active_support/core_ext/blank.rb activesupport/lib/active_support/core_ext/duplicable.rb activesupport/lib/active_support/core_ext/kernel/agnostics.rb activesupport/lib/active_support/core_ext/object/conversions.rb activesupport/lib/active_support/core_ext/object/extending.rb activesupport/lib/active_support/core_ext/object/instance_variables.rb activesupport/lib/active_support/core_ext/object/misc.rb activesupport/lib/active_support/dependencies.rb activesupport/lib/active_support/json/encoders/object.rb activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb
Parent: | Object

Same as above, except in Object.

Methods
  • acts_like?
  • blank?
  • duplicable?
  • find_hidden_method
  • instance_exec
  • instance_variable_defined?
  • method_added
  • returning
  • to_json
  • to_param
  • to_param
  • to_query
  • unloadable
  • with_options
Included Modules
  • InstanceExecMethods
Public Class methods
find_hidden_method(name)

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 90
90:     def find_hidden_method(name)
91:       nil
92:     end
method_added(name)

Detect method additions to Object and remove them in the BlankSlate class.

[ show source ]

    # File activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb, line 83
83:     def method_added(name)
84:       result = blank_slate_method_added(name)
85:       return result if self != Object
86:       BlankSlate.hide(name)
87:       result
88:     end
Public Instance methods
acts_like?(duck)

A duck-type assistant method. For example, ActiveSupport extends Date to define an acts_like_date? method, and extends Time to define acts_like_time?. As a result, we can do "x.acts_like?(:time)" and "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that we want to act like Time simply need to define an acts_like_time? method.

[ show source ]

    # File activesupport/lib/active_support/core_ext/object/misc.rb, line 56
56:   def acts_like?(duck)
57:     respond_to? "acts_like_#{duck}?"
58:   end
blank?()

An object is blank if it‘s nil, empty, or a whitespace string. For example, "", " ", nil, [], and {} are blank.

This simplifies

  if !address.nil? && !address.empty?

to

  if !address.blank?

[ show source ]

    # File activesupport/lib/active_support/core_ext/blank.rb, line 9
 9:   def blank?
10:     respond_to?(:empty?) ? empty? : !self
11:   end
duplicable?()

Can you safely .dup this object? False for nil, false, true, symbols, and numbers; true otherwise.

[ show source ]

   # File activesupport/lib/active_support/core_ext/duplicable.rb, line 4
4:   def duplicable?
5:     true
6:   end
instance_exec(*args, &block)

Evaluate the block with the given arguments within the context of this object, so self is set to the method receiver.

From Mauricio‘s eigenclass.org/hiki/bounded+space+instance_exec

[ show source ]

    # File activesupport/lib/active_support/core_ext/object/extending.rb, line 41
41:     def instance_exec(*args, &block)
42:       begin
43:         old_critical, Thread.critical = Thread.critical, true
44:         n = 0
45:         n += 1 while respond_to?(method_name = "__instance_exec#{n}")
46:         InstanceExecMethods.module_eval { define_method(method_name, &block) }
47:       ensure
48:         Thread.critical = old_critical
49:       end
50:
51:       begin
52:         send(method_name, *args)
53:       ensure
54:         InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil
55:       end
56:     end
instance_variable_defined?(variable)

[ show source ]

   # File activesupport/lib/active_support/core_ext/object/instance_variables.rb, line 4
4:     def instance_variable_defined?(variable)
5:       instance_variables.include?(variable.to_s)
6:     end
returning(value) {|value| ...}

A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.

  def foo
    returning values = [] do
      values << 'bar'
      values << 'baz'
    end
  end

  foo # => ['bar', 'baz']

  def foo
    returning [] do |values|
      values << 'bar'
      values << 'baz'
    end
  end

  foo # => ['bar', 'baz']

[ show source ]

    # File activesupport/lib/active_support/core_ext/object/misc.rb, line 27
27:   def returning(value)
28:     yield(value)
29:     value
30:   end
to_json(options = {})

Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.

[ show source ]

   # File activesupport/lib/active_support/json/encoders/object.rb, line 3
3:   def to_json(options = {})
4:     ActiveSupport::JSON.encode(instance_values, options)
5:   end
to_param()

Alias of to_s.

[ show source ]

   # File activesupport/lib/active_support/core_ext/object/conversions.rb, line 3
3:   def to_param
4:     to_s
5:   end
to_param()

[ show source ]

   # File actionpack/lib/action_controller/routing.rb, line 7
7:   def to_param
8:     to_s
9:   end
to_query(key)

Converts an object into a string suitable for use as a URL query string, using the given key as the param name.

Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.

[ show source ]

    # File activesupport/lib/active_support/core_ext/object/conversions.rb, line 11
11:   def to_query(key)
12:     "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
13:   end
unloadable(const_desc)

Mark the given constant as unloadable. Unloadable constants are removed each time dependencies are cleared.

Note that marking a constant for unloading need only be done once. Setup or init scripts may list each unloadable constant that may need unloading; each constant will be removed for every subsequent clear, as opposed to for the first clear.

The provided constant descriptor may be a (non-anonymous) module or class, or a qualified constant name as a string or symbol.

Returns true if the constant was not previously marked for unloading, false otherwise.

[ show source ]

     # File activesupport/lib/active_support/dependencies.rb, line 515
515:   def unloadable(const_desc)
516:     Dependencies.mark_for_unload const_desc
517:   end
with_options(options) {|ActiveSupport::OptionMerger.new(self, options)| ...}

An elegant way to refactor out common options

  with_options :order => 'created_at', :class_name => 'Comment' do |post|
    post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
    post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
    post.has_many :all_comments
  end

Can also be used with an explicit receiver:

  map.with_options :controller => "people" do |people|
    people.connect "/people",     :action => "index"
    people.connect "/people/:id", :action => "show"
  end

[ show source ]

    # File activesupport/lib/active_support/core_ext/object/misc.rb, line 47
47:   def with_options(options)
48:     yield ActiveSupport::OptionMerger.new(self, options)
49:   end


Class: SourceAnnotationExtractor

Class
SourceAnnotationExtractor
In: | railties/lib/source_annotation_extractor.rb
Parent: | Object
Methods
  • display
  • enumerate
  • extract_annotations_from
  • find
  • find_in
  • new
Classes and Modules
Class SourceAnnotationExtractor::Annotation
Attributes
[R] tag
Public Class methods
enumerate(tag, options={})

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 10
10:   def self.enumerate(tag, options={})
11:     extractor = new(tag)
12:     extractor.display(extractor.find, options)
13:   end
new(tag)

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 17
17:   def initialize(tag)
18:     @tag = tag
19:   end
Public Instance methods
display(results, options={})

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 53
53:   def display(results, options={})
54:     results.keys.sort.each do |file|
55:       puts "#{file}:"
56:       results[file].each do |note|
57:         puts "  * #{note.to_s(options)}"
58:       end
59:       puts
60:     end
61:   end
extract_annotations_from(file, pattern)

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 43
43:   def extract_annotations_from(file, pattern)
44:     lineno = 0
45:     result = File.readlines(file).inject([]) do |list, line|
46:       lineno += 1
47:       next list unless line =~ pattern
48:       list << Annotation.new(lineno, $1, $2)
49:     end
50:     result.empty? ? {} : { file => result }
51:   end
find(dirs=%w(app lib test))

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 21
21:   def find(dirs=%w(app lib test))
22:     dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
23:   end
find_in(dir)

[ show source ]

    # File railties/lib/source_annotation_extractor.rb, line 25
25:   def find_in(dir)
26:     results = {}
27:
28:     Dir.glob("#{dir}/*") do |item|
29:       next if File.basename(item)[0] == ?.
30:
31:       if File.directory?(item)
32:         results.update(find_in(item))
33:       elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
34:         results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
35:       elsif item =~ /\.(rhtml|erb)$/
36:         results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
37:       end
38:     end
39:
40:     results
41:   end


Class: SourceAnnotationExtractor::Annotation

Class
SourceAnnotationExtractor::Annotation
In: | railties/lib/source_annotation_extractor.rb
Parent: | Struct.new(:line, :tag, :text)
Methods
  • to_s
Public Instance methods
to_s(options={})

[ show source ]

   # File railties/lib/source_annotation_extractor.rb, line 3
3:     def to_s(options={})
4:       s = "[%3d] " % line
5:       s << "[#{tag}] " if options[:tag]
6:       s << text
7:     end


Class: TimeZone

Class
TimeZone
In: | activesupport/lib/active_support/values/time_zone.rb
Parent: | Object

A value object representing a time zone. A time zone is simply a named offset (in seconds) from GMT. Note that two time zone objects are only equivalent if they have both the same offset, and the same name.

A TimeZone instance may be used to convert a Time value to the corresponding time zone.

The class also includes all, which returns a list of all TimeZone objects.

Methods
  • <=>
  • []
  • adjust
  • all
  • create
  • formatted_offset
  • new
  • new
  • now
  • to_s
  • today
  • unadjust
  • us_zones
Included Modules
  • Comparable
Constants
US_ZONES | = | /US|Arizona|Indiana|Hawaii|Alaska/ unless defined?(US_ZONES)
 | A regular expression that matches the names of all time zones in the USA.
Attributes
[R] | name
[R] | utc_offset
Public Class methods
[](arg)

Locate a specific time zone object. If the argument is a string, it is interpreted to mean the name of the timezone to locate. If it is a numeric value it is either the hour offset, or the second offset, of the timezone to find. (The first one with that offset will be returned.) Returns nil if no such time zone is known to the system.

[ show source ]

     # File activesupport/lib/active_support/values/time_zone.rb, line 159
159:     def [](arg)
160:       case arg
161:         when String
162:           all.find { |z| z.name == arg }
163:         when Numeric
164:           arg *= 3600 if arg.abs <= 13
165:           all.find { |z| z.utc_offset == arg.to_i }
166:         else
167:           raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
168:       end
169:     end
all()

Return an array of all TimeZone objects. There are multiple TimeZone objects per time zone, in many cases, to make it easier for users to find their own time zone.

[ show source ]

     # File activesupport/lib/active_support/values/time_zone.rb, line 94
 94:     def all
 95:       unless @@zones
 96:         @@zones = []
 97:         [[-43_200, "International Date Line West" ],
 98:          [-39_600, "Midway Island", "Samoa" ],
 99:          [-36_000, "Hawaii" ],
100:          [-32_400, "Alaska" ],
101:          [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
102:          [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
103:                    "Arizona" ],
104:          [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
105:                    "Mexico City", "Monterrey", "Central America" ],
106:          [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
107:                    "Lima", "Quito" ],
108:          [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
109:          [-12_600, "Newfoundland" ],
110:          [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
111:          [ -7_200, "Mid-Atlantic" ],
112:          [ -3_600, "Azores", "Cape Verde Is." ],
113:          [      0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
114:                    "Monrovia" ],
115:          [  3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
116:                    "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
117:                    "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
118:                    "Bern", "Rome", "Stockholm", "Vienna",
119:                    "West Central Africa" ],
120:          [  7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
121:                    "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
122:                    "Jerusalem", "Harare", "Pretoria" ],
123:          [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
124:                    "Nairobi", "Baghdad" ],
125:          [ 12_600, "Tehran" ],
126:          [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
127:          [ 16_200, "Kabul" ],
128:          [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
129:          [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
130:          [ 20_700, "Kathmandu" ],
131:          [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
132:                    "Novosibirsk" ],
133:          [ 23_400, "Rangoon" ],
134:          [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
135:          [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
136:                    "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
137:                    "Ulaan Bataar" ],
138:          [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
139:          [ 34_200, "Darwin", "Adelaide" ],
140:          [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
141:                    "Vladivostok", "Guam", "Port Moresby" ],
142:          [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
143:          [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
144:                    "Wellington" ],
145:          [ 46_800, "Nuku'alofa" ]].
146:         each do |offset, *places|
147:           places.each { |place| @@zones << create(place, offset).freeze }
148:         end
149:         @@zones.sort!
150:       end
151:       @@zones
152:     end
create(name, offset)

Create a new TimeZone instance with the given name and offset.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 78
78:     def create(name, offset)
79:       zone = allocate
80:       zone.send!(:initialize, name, offset)
81:       zone
82:     end
new(name, utc_offset)

Create a new TimeZone object with the given name and offset. The offset is the number of seconds that this time zone is offset from UTC (GMT). Seconds were chosen as the offset unit because that is the unit that Ruby uses to represent time zone offsets (see Time#utc_offset).

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 18
18:   def initialize(name, utc_offset)
19:     @name = name
20:     @utc_offset = utc_offset
21:   end
new(name)

Return a TimeZone instance with the given name, or nil if no such TimeZone instance exists. (This exists to support the use of this class with the composed_of macro.)

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 87
87:     def new(name)
88:       self[name]
89:     end
us_zones()

A convenience method for returning a collection of TimeZone objects for time zones in the USA.

[ show source ]

     # File activesupport/lib/active_support/values/time_zone.rb, line 177
177:     def us_zones
178:       all.find_all { |z| z.name =~ US_ZONES }
179:     end
Public Instance methods
<=>(zone)

Compare this time zone to the parameter. The two are comapred first on their offsets, and then by name.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 63
63:   def <=>(zone)
64:     result = (utc_offset <=> zone.utc_offset)
65:     result = (name <=> zone.name) if result == 0
66:     result
67:   end
adjust(time)

Adjust the given time to the time zone represented by self.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 47
47:   def adjust(time)
48:     time = time.to_time unless time.is_a?(::Time)
49:     time + utc_offset - time.utc_offset
50:   end
formatted_offset( colon=true )

Returns the offset of this time zone as a formatted string, of the format "+HH:MM". If the offset is zero, this returns the empty string. If colon is false, a colon will not be inserted into the result.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 27
27:   def formatted_offset( colon=true )
28:     return "" if utc_offset == 0
29:     sign = (utc_offset < 0 ? -1 : 1)
30:     hours = utc_offset.abs / 3600
31:     minutes = (utc_offset.abs % 3600) / 60
32:     "%+03d%s%02d" % [ hours * sign, colon ? ":" : "", minutes ]
33:   end
now()

Compute and return the current time, in the time zone represented by self.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 37
37:   def now
38:     adjust(Time.now)
39:   end
to_s()

Returns a textual representation of this time zone.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 70
70:   def to_s
71:     "(UTC#{formatted_offset}) #{name}"
72:   end
today()

Return the current date in this time zone.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 42
42:   def today
43:     now.to_date
44:   end
unadjust(time)

Reinterprets the given time value as a time in the current time zone, and then adjusts it to return the corresponding time in the local time zone.

[ show source ]

    # File activesupport/lib/active_support/values/time_zone.rb, line 55
55:   def unadjust(time)
56:     time = time.to_time unless time.is_a?(::Time)
57:     time = time.localtime
58:     time - utc_offset - time.utc_offset
59:   end


Class: XmlSimple

Class
XmlSimple
In: | activesupport/lib/active_support/core_ext/hash/conversions.rb activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb
Parent: | Object

Easy API to maintain XML (especially configuration files).

Methods
  • new
  • xml_in
  • xml_in
  • xml_in_string
  • xml_in_string
  • xml_out
  • xml_out
Included Modules
  • REXML
Classes and Modules
Class XmlSimple::Cache
Constants
KNOWN_OPTIONS | = | { 'in' => %w( keyattr keeproot forcecontent contentkey noattr searchpath forcearray suppressempty anonymoustag cache grouptags normalisespace normalizespace variables varattr keytosymbol ), 'out' => %w( keyattr keeproot contentkey noattr rootname xmldeclaration outputfile noescape suppressempty anonymoustag indent grouptags noindent )
 | Declare options that are valid for xml_in and xml_out.
DEF_KEY_ATTRIBUTES | = | []
 | Define some reasonable defaults.
DEF_ROOT_NAME | = | 'opt'
DEF_CONTENT_KEY | = | 'content'
DEF_XML_DECLARATION | = | "<?xml version='1.0' standalone='yes'?>"
DEF_ANONYMOUS_TAG | = | 'anon'
DEF_FORCE_ARRAY | = | true
DEF_INDENTATION | = | ' '
DEF_KEY_TO_SYMBOL | = | false
Public Class methods
new(defaults = nil)

Creates and intializes a new XmlSimple object.

defaults: Default values for options.

[ show source ]

     # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 128
128:   def initialize(defaults = nil)
129:     unless defaults.nil? || defaults.instance_of?(Hash)
130:       raise ArgumentError, "Options have to be a Hash."
131:     end
132:     @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq)
133:     @options = Hash.new
134:     @_var_values = nil
135:   end
xml_in(string = nil, options = nil)

This is the functional version of the instance method xml_in.

[ show source ]

     # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 201
201:   def XmlSimple.xml_in(string = nil, options = nil)
202:     xml_simple = XmlSimple.new
203:     xml_simple.xml_in(string, options)
204:   end
xml_in_string(string, options = nil)

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/conversions.rb, line 23
23:   def self.xml_in_string(string, options = nil)
24:     new.xml_in_string(string, options)
25:   end
xml_out(hash, options = nil)

This is the functional version of the instance method xml_out.

[ show source ]

     # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 257
257:   def XmlSimple.xml_out(hash, options = nil)
258:     xml_simple = XmlSimple.new
259:     xml_simple.xml_out(hash, options)
260:   end
Public Instance methods
xml_in(string = nil, options = nil)

Converts an XML document in the same way as the Perl module XML::Simple.

string: XML source. Could be one of the following:
  • nil: Tries to load and parse ’<scriptname>.xml’.
  • filename: Tries to load and parse filename.
  • IO object: Reads from object until EOF is detected and parses result.
  • XML string: Parses string.
options: Options to be used.

[ show source ]

     # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 149
149:   def xml_in(string = nil, options = nil)
150:     handle_options('in', options)
151:
152:     # If no XML string or filename was supplied look for scriptname.xml.
153:     if string.nil?
154:       string = File::basename($0)
155:       string.sub!(/\.[^.]+$/, '')
156:       string += '.xml'
157:
158:       directory = File::dirname($0)
159:       @options['searchpath'].unshift(directory) unless directory.nil?
160:     end
161:
162:     if string.instance_of?(String)
163:       if string =~ /<.*?>/m
164:         @doc = parse(string)
165:       elsif string == '-'
166:         @doc = parse($stdin.readlines.to_s)
167:       else
168:         filename = find_xml_file(string, @options['searchpath'])
169:
170:         if @options.has_key?('cache')
171:           @options['cache'].each { |scheme|
172:             case(scheme)
173:             when 'storable'
174:               content = @@cache.restore_storable(filename)
175:             when 'mem_share'
176:               content = @@cache.restore_mem_share(filename)
177:             when 'mem_copy'
178:               content = @@cache.restore_mem_copy(filename)
179:             else
180:               raise ArgumentError, "Unsupported caching scheme: <#{scheme}>."
181:             end
182:             return content if content
183:           }
184:         end
185:
186:         @doc = load_xml_file(filename)
187:       end
188:     elsif string.kind_of?(IO) || string.kind_of?(StringIO)
189:       @doc = parse(string.readlines.to_s)
190:     else
191:       raise ArgumentError, "Could not parse object of type: <#{string.type}>."
192:     end
193:
194:     result = collapse(@doc.root)
195:     result = @options['keeproot'] ? merge({}, @doc.root.name, result) : result
196:     put_into_cache(result, filename)
197:     result
198:   end
xml_in_string(string, options = nil)

Same as xml_in but doesn‘t try to smartly shoot itself in the foot.

[ show source ]

    # File activesupport/lib/active_support/core_ext/hash/conversions.rb, line 10
10:   def xml_in_string(string, options = nil)
11:     handle_options('in', options)
12:
13:     @doc = parse(string)
14:     result = collapse(@doc.root)
15:
16:     if @options['keeproot']
17:       merge({}, @doc.root.name, result)
18:     else
19:       result
20:     end
21:   end
xml_out(ref, options = nil)

Converts a data structure into an XML document.

ref: | Reference to data structure to be converted into XML.
options: | Options to be used.

[ show source ]

     # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 212
212:   def xml_out(ref, options = nil)
213:     handle_options('out', options)
214:     if ref.instance_of?(Array)
215:       ref = { @options['anonymoustag'] => ref }
216:     end
217:
218:     if @options['keeproot']
219:       keys = ref.keys
220:       if keys.size == 1
221:         ref = ref[keys[0]]
222:         @options['rootname'] = keys[0]
223:       end
224:     elsif @options['rootname'] == ''
225:       if ref.instance_of?(Hash)
226:         refsave = ref
227:         ref = {}
228:         refsave.each { |key, value|
229:           if !scalar(value)
230:             ref[key] = value
231:           else
232:             ref[key] = [ value.to_s ]
233:           end
234:         }
235:       end
236:     end
237:
238:     @ancestors = []
239:     xml = value_to_xml(ref, @options['rootname'], '')
240:     @ancestors = nil
241:
242:     if @options['xmldeclaration']
243:       xml = @options['xmldeclaration'] + "\n" + xml
244:     end
245:
246:     if @options.has_key?('outputfile')
247:       if @options['outputfile'].kind_of?(IO)
248:         return @options['outputfile'].write(xml)
249:       else
250:         File.open(@options['outputfile'], "w") { |file| file.write(xml) }
251:       end
252:     end
253:     xml
254:   end


Class: XmlSimple::Cache

Class
XmlSimple::Cache
In: | activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb
Parent: | Object

A simple cache for XML documents that were already transformed by xml_in.

Methods
  • new
  • restore_mem_copy
  • restore_mem_share
  • restore_storable
  • save_mem_copy
  • save_mem_share
  • save_storable
Public Class methods
new()

Creates and initializes a new Cache object.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 20
20:     def initialize
21:       @mem_share_cache = {}
22:       @mem_copy_cache  = {}
23:     end
Public Instance methods
restore_mem_copy(filename)

Restores a data structure from a memory cache. If restoring the data structure failed for any reason, nil will be returned.

filename: Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 87
87:     def restore_mem_copy(filename)
88:       data = get_from_memory_cache(filename, @mem_share_cache)
89:       data = Marshal.load(data) unless data.nil?
90:       data
91:     end
restore_mem_share(filename)

Restores a data structure from a shared memory cache. You should consider these elements as "read only". If restoring the data structure failed for any reason, nil will be returned.

filename: Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 67
67:     def restore_mem_share(filename)
68:       get_from_memory_cache(filename, @mem_share_cache)
69:     end
restore_storable(filename)

Restores a data structure from a file. If restoring the data structure failed for any reason, nil will be returned.

filename: Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 41
41:     def restore_storable(filename)
42:       cache_file = get_cache_filename(filename)
43:       return nil unless File::exist?(cache_file)
44:       return nil unless File::mtime(cache_file).to_i > File::mtime(filename).to_i
45:       data = nil
46:       File.open(cache_file) { |f| data = Marshal.load(f) }
47:       data
48:     end
save_mem_copy(data, filename)

Copies a data structure to a memory cache.

data: | Data structure to be copied.
filename: | Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 77
77:     def save_mem_copy(data, filename)
78:       @mem_share_cache[filename] = [Time::now.to_i, Marshal.dump(data)]
79:     end
save_mem_share(data, filename)

Saves a data structure in a shared memory cache.

data: | Data structure to be saved.
filename: | Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 56
56:     def save_mem_share(data, filename)
57:       @mem_share_cache[filename] = [Time::now.to_i, data]
58:     end
save_storable(data, filename)

Saves a data structure into a file.

data: | Data structure to be saved.
filename: | Name of the file belonging to the data structure.

[ show source ]

    # File activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb, line 31
31:     def save_storable(data, filename)
32:       cache_file = get_cache_filename(filename)
33:       File.open(cache_file, "w+") { |f| Marshal.dump(data, f) }
34:     end


File: basic_object.rb

File
basic_object.rb
Path: | activesupport/lib/active_support/basic_object.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Ruby 1.9 introduces BasicObject. Use Builder‘s BlankSlate until then.

Required Files
  • blankslate
Constants
BasicObject = BlankSlate


File: buffered_logger.rb

File
buffered_logger.rb
Path: | activesupport/lib/active_support/buffered_logger.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: clean_logger.rb

File
clean_logger.rb
Path: | activesupport/lib/active_support/clean_logger.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • logger
  • active_support/core_ext/class/attribute_accessors


File: core_ext.rb

File
core_ext.rb
Path: | activesupport/lib/active_support/core_ext.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: array.rb

File
array.rb
Path: | activesupport/lib/active_support/core_ext/array.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • active_support/core_ext/array/access
  • active_support/core_ext/array/conversions
  • active_support/core_ext/array/extract_options
  • active_support/core_ext/array/grouping
  • active_support/core_ext/array/random_access


File: access.rb

File
access.rb
Path: | activesupport/lib/active_support/core_ext/array/access.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/array/conversions.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • builder


File: extract_options.rb

File
extract_options.rb
Path: | activesupport/lib/active_support/core_ext/array/extract_options.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: grouping.rb

File
grouping.rb
Path: | activesupport/lib/active_support/core_ext/array/grouping.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • enumerator


File: random_access.rb

File
random_access.rb
Path: | activesupport/lib/active_support/core_ext/array/random_access.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: bigdecimal.rb

File
bigdecimal.rb
Path: | activesupport/lib/active_support/core_ext/bigdecimal.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • bigdecimal
  • active_support/core_ext/bigdecimal/conversions


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: blank.rb

File
blank.rb
Path: | activesupport/lib/active_support/core_ext/blank.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: cgi.rb

File
cgi.rb
Path: | activesupport/lib/active_support/core_ext/cgi.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • active_support/core_ext/cgi/escape_skipping_slashes


File: escape_skipping_slashes.rb

File
escape_skipping_slashes.rb
Path: | activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: class.rb

File
class.rb
Path: | activesupport/lib/active_support/core_ext/class.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • active_support/core_ext/class/attribute_accessors
  • active_support/core_ext/class/inheritable_attributes
  • active_support/core_ext/class/removal
  • active_support/core_ext/class/delegating_attributes


File: attribute_accessors.rb

File
attribute_accessors.rb
Path: | activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Extends the class object with class and instance accessors for class attributes, just like the native attr* accessors for instance attributes.


File: delegating_attributes.rb

File
delegating_attributes.rb
Path: | activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

These class attributes behave something like the class inheritable accessors. But instead of copying the hash over at the time the subclass is first defined, the accessors simply delegate to their superclass unless they have been given a specific value. This stops the strange situation where values set after class definition don‘t get applied to subclasses.


File: inheritable_attributes.rb

File
inheritable_attributes.rb
Path: | activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Retain for backward compatibility. Methods are now included in Class.


File: removal.rb

File
removal.rb
Path: | activesupport/lib/active_support/core_ext/class/removal.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: date.rb

File
date.rb
Path: | activesupport/lib/active_support/core_ext/date.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008

Required Files
  • date
  • active_support/core_ext/date/behavior
  • active_support/core_ext/date/calculations
  • active_support/core_ext/date/conversions


File: behavior.rb

File
behavior.rb
Path: | activesupport/lib/active_support/core_ext/date/behavior.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: calculations.rb

File
calculations.rb
Path: | activesupport/lib/active_support/core_ext/date/calculations.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/date/conversions.rb
Modified: | Sun Mar 02 11:08:48 -0700 2008


File: date_time.rb

File
date_time.rb
Path: | activesupport/lib/active_support/core_ext/date_time.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • date
  • active_support/core_ext/time/behavior
  • active_support/core_ext/date_time/calculations
  • active_support/core_ext/date_time/conversions


File: calculations.rb

File
calculations.rb
Path: | activesupport/lib/active_support/core_ext/date_time/calculations.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • rational


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/date_time/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: duplicable.rb

File
duplicable.rb
Path: | activesupport/lib/active_support/core_ext/duplicable.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: enumerable.rb

File
enumerable.rb
Path: | activesupport/lib/active_support/core_ext/enumerable.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: exception.rb

File
exception.rb
Path: | activesupport/lib/active_support/core_ext/exception.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: file.rb

File
file.rb
Path: | activesupport/lib/active_support/core_ext/file.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • tempfile


File: float.rb

File
float.rb
Path: | activesupport/lib/active_support/core_ext/float.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/float/rounding


File: rounding.rb

File
rounding.rb
Path: | activesupport/lib/active_support/core_ext/float/rounding.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: hash.rb

File
hash.rb
Path: | activesupport/lib/active_support/core_ext/hash.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/hash/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • date
  • cgi
  • base64
  • builder
  • xmlsimple


File: diff.rb

File
diff.rb
Path: | activesupport/lib/active_support/core_ext/hash/diff.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: except.rb

File
except.rb
Path: | activesupport/lib/active_support/core_ext/hash/except.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • set


File: indifferent_access.rb

File
indifferent_access.rb
Path: | activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

This class has dubious semantics and we only have it so that people can write params[:key] instead of params[‘key’]


File: keys.rb

File
keys.rb
Path: | activesupport/lib/active_support/core_ext/hash/keys.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: reverse_merge.rb

File
reverse_merge.rb
Path: | activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: slice.rb

File
slice.rb
Path: | activesupport/lib/active_support/core_ext/hash/slice.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • set


File: integer.rb

File
integer.rb
Path: | activesupport/lib/active_support/core_ext/integer.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/integer/even_odd
  • active_support/core_ext/integer/inflections


File: even_odd.rb

File
even_odd.rb
Path: | activesupport/lib/active_support/core_ext/integer/even_odd.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: inflections.rb

File
inflections.rb
Path: | activesupport/lib/active_support/core_ext/integer/inflections.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/inflector


File: kernel.rb

File
kernel.rb
Path: | activesupport/lib/active_support/core_ext/kernel.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/kernel/daemonizing
  • active_support/core_ext/kernel/reporting
  • active_support/core_ext/kernel/agnostics
  • active_support/core_ext/kernel/requires
  • active_support/core_ext/kernel/debugger


File: agnostics.rb

File
agnostics.rb
Path: | activesupport/lib/active_support/core_ext/kernel/agnostics.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: daemonizing.rb

File
daemonizing.rb
Path: | activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: debugger.rb

File
debugger.rb
Path: | activesupport/lib/active_support/core_ext/kernel/debugger.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: reporting.rb

File
reporting.rb
Path: | activesupport/lib/active_support/core_ext/kernel/reporting.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: requires.rb

File
requires.rb
Path: | activesupport/lib/active_support/core_ext/kernel/requires.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • rubygems


File: load_error.rb

File
load_error.rb
Path: | activesupport/lib/active_support/core_ext/load_error.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: logger.rb

File
logger.rb
Path: | activesupport/lib/active_support/core_ext/logger.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Adds the ‘around_level’ method to Logger.


File: module.rb

File
module.rb
Path: | activesupport/lib/active_support/core_ext/module.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/module/inclusion
  • active_support/core_ext/module/attribute_accessors
  • active_support/core_ext/module/attr_internal
  • active_support/core_ext/module/attr_accessor_with_default
  • active_support/core_ext/module/delegation
  • active_support/core_ext/module/introspection
  • active_support/core_ext/module/loading
  • active_support/core_ext/module/aliasing


File: aliasing.rb

File
aliasing.rb
Path: | activesupport/lib/active_support/core_ext/module/aliasing.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: attr_accessor_with_default.rb

File
attr_accessor_with_default.rb
Path: | activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: attr_internal.rb

File
attr_internal.rb
Path: | activesupport/lib/active_support/core_ext/module/attr_internal.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: attribute_accessors.rb

File
attribute_accessors.rb
Path: | activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Extends the module object with module and instance accessors for class attributes, just like the native attr* accessors for instance attributes.


File: delegation.rb

File
delegation.rb
Path: | activesupport/lib/active_support/core_ext/module/delegation.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: inclusion.rb

File
inclusion.rb
Path: | activesupport/lib/active_support/core_ext/module/inclusion.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: introspection.rb

File
introspection.rb
Path: | activesupport/lib/active_support/core_ext/module/introspection.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: loading.rb

File
loading.rb
Path: | activesupport/lib/active_support/core_ext/module/loading.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: name_error.rb

File
name_error.rb
Path: | activesupport/lib/active_support/core_ext/name_error.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Add a missing_name method to NameError instances.


File: numeric.rb

File
numeric.rb
Path: | activesupport/lib/active_support/core_ext/numeric.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/numeric/time
  • active_support/core_ext/numeric/bytes


File: bytes.rb

File
bytes.rb
Path: | activesupport/lib/active_support/core_ext/numeric/bytes.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: time.rb

File
time.rb
Path: | activesupport/lib/active_support/core_ext/numeric/time.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: object.rb

File
object.rb
Path: | activesupport/lib/active_support/core_ext/object.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/object/conversions
  • active_support/core_ext/object/extending
  • active_support/core_ext/object/instance_variables
  • active_support/core_ext/object/misc


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/object/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: extending.rb

File
extending.rb
Path: | activesupport/lib/active_support/core_ext/object/extending.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: instance_variables.rb

File
instance_variables.rb
Path: | activesupport/lib/active_support/core_ext/object/instance_variables.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: misc.rb

File
misc.rb
Path: | activesupport/lib/active_support/core_ext/object/misc.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: pathname.rb

File
pathname.rb
Path: | activesupport/lib/active_support/core_ext/pathname.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • pathname
  • active_support/core_ext/pathname/clean_within


File: clean_within.rb

File
clean_within.rb
Path: | activesupport/lib/active_support/core_ext/pathname/clean_within.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: proc.rb

File
proc.rb
Path: | activesupport/lib/active_support/core_ext/proc.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: range.rb

File
range.rb
Path: | activesupport/lib/active_support/core_ext/range.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/range/conversions
  • active_support/core_ext/range/overlaps
  • active_support/core_ext/range/include_range
  • active_support/core_ext/range/blockless_step


File: blockless_step.rb

File
blockless_step.rb
Path: | activesupport/lib/active_support/core_ext/range/blockless_step.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/range/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: include_range.rb

File
include_range.rb
Path: | activesupport/lib/active_support/core_ext/range/include_range.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: overlaps.rb

File
overlaps.rb
Path: | activesupport/lib/active_support/core_ext/range/overlaps.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: string.rb

File
string.rb
Path: | activesupport/lib/active_support/core_ext/string.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/string/inflections
  • active_support/core_ext/string/conversions
  • active_support/core_ext/string/access
  • active_support/core_ext/string/starts_ends_with
  • active_support/core_ext/string/iterators
  • active_support/core_ext/string/unicode
  • active_support/core_ext/string/xchar


File: access.rb

File
access.rb
Path: | activesupport/lib/active_support/core_ext/string/access.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/string/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • parsedate


File: inflections.rb

File
inflections.rb
Path: | activesupport/lib/active_support/core_ext/string/inflections.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/inflector


File: iterators.rb

File
iterators.rb
Path: | activesupport/lib/active_support/core_ext/string/iterators.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • strscan


File: starts_ends_with.rb

File
starts_ends_with.rb
Path: | activesupport/lib/active_support/core_ext/string/starts_ends_with.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: unicode.rb

File
unicode.rb
Path: | activesupport/lib/active_support/core_ext/string/unicode.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: xchar.rb

File
xchar.rb
Path: | activesupport/lib/active_support/core_ext/string/xchar.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • fast_xs


File: symbol.rb

File
symbol.rb
Path: | activesupport/lib/active_support/core_ext/symbol.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: test.rb

File
test.rb
Path: | activesupport/lib/active_support/core_ext/test.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/core_ext/test/unit/assertions


File: assertions.rb

File
assertions.rb
Path: | activesupport/lib/active_support/core_ext/test/unit/assertions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: time.rb

File
time.rb
Path: | activesupport/lib/active_support/core_ext/time.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • date
  • time
  • active_support/core_ext/time/behavior
  • active_support/core_ext/time/calculations
  • active_support/core_ext/time/conversions


File: behavior.rb

File
behavior.rb
Path: | activesupport/lib/active_support/core_ext/time/behavior.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: calculations.rb

File
calculations.rb
Path: | activesupport/lib/active_support/core_ext/time/calculations.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: conversions.rb

File
conversions.rb
Path: | activesupport/lib/active_support/core_ext/time/conversions.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: dependencies.rb

File
dependencies.rb
Path: | activesupport/lib/active_support/dependencies.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • set
  • active_support/core_ext/module/attribute_accessors
  • active_support/core_ext/load_error
  • active_support/core_ext/kernel


File: deprecation.rb

File
deprecation.rb
Path: | activesupport/lib/active_support/deprecation.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • yaml
  • test/unit/error


File: duration.rb

File
duration.rb
Path: | activesupport/lib/active_support/duration.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: inflections.rb

File
inflections.rb
Path: | activesupport/lib/active_support/inflections.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: inflector.rb

File
inflector.rb
Path: | activesupport/lib/active_support/inflector.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • singleton


File: json.rb

File
json.rb
Path: | activesupport/lib/active_support/json.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/json/encoding
  • active_support/json/decoding


File: decoding.rb

File
decoding.rb
Path: | activesupport/lib/active_support/json/decoding.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • yaml
  • strscan


File: date.rb

File
date.rb
Path: | activesupport/lib/active_support/json/encoders/date.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: date_time.rb

File
date_time.rb
Path: | activesupport/lib/active_support/json/encoders/date_time.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: enumerable.rb

File
enumerable.rb
Path: | activesupport/lib/active_support/json/encoders/enumerable.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: false_class.rb

File
false_class.rb
Path: | activesupport/lib/active_support/json/encoders/false_class.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: hash.rb

File
hash.rb
Path: | activesupport/lib/active_support/json/encoders/hash.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: nil_class.rb

File
nil_class.rb
Path: | activesupport/lib/active_support/json/encoders/nil_class.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: numeric.rb

File
numeric.rb
Path: | activesupport/lib/active_support/json/encoders/numeric.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: object.rb

File
object.rb
Path: | activesupport/lib/active_support/json/encoders/object.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: regexp.rb

File
regexp.rb
Path: | activesupport/lib/active_support/json/encoders/regexp.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: string.rb

File
string.rb
Path: | activesupport/lib/active_support/json/encoders/string.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: symbol.rb

File
symbol.rb
Path: | activesupport/lib/active_support/json/encoders/symbol.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: time.rb

File
time.rb
Path: | activesupport/lib/active_support/json/encoders/time.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: true_class.rb

File
true_class.rb
Path: | activesupport/lib/active_support/json/encoders/true_class.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: encoding.rb

File
encoding.rb
Path: | activesupport/lib/active_support/json/encoding.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/json/variable
  • active_support/json/encoders/object


File: variable.rb

File
variable.rb
Path: | activesupport/lib/active_support/json/variable.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: multibyte.rb

File
multibyte.rb
Path: | activesupport/lib/active_support/multibyte.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/multibyte/chars


File: chars.rb

File
chars.rb
Path: | activesupport/lib/active_support/multibyte/chars.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/multibyte/handlers/utf8_handler
  • active_support/multibyte/handlers/passthru_handler
  • utf8proc_native
  • active_support/multibyte/handlers/utf8_handler_proc


File: generate_tables.rb

File
generate_tables.rb
Path: | activesupport/lib/active_support/multibyte/generators/generate_tables.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • open-uri
  • tmpdir


File: passthru_handler.rb

File
passthru_handler.rb
Path: | activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Chars uses this handler when $KCODE is not set to ‘UTF8’. Because this handler doesn‘t define any methods all call will be forwarded to String.


File: utf8_handler.rb

File
utf8_handler.rb
Path: | activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Contains all the handlers and helper classes


File: utf8_handler_proc.rb

File
utf8_handler_proc.rb
Path: | activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Methods in this handler call functions in the utf8proc ruby extension. These are significantly faster than the pure ruby versions. Chars automatically uses this handler when it can load the utf8proc extension. For documentation on handler methods see UTF8Handler.


File: option_merger.rb

File
option_merger.rb
Path: | activesupport/lib/active_support/option_merger.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: ordered_options.rb

File
ordered_options.rb
Path: | activesupport/lib/active_support/ordered_options.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

OrderedHash is namespaced to prevent conflicts with other implementations


File: test_case.rb

File
test_case.rb
Path: | activesupport/lib/active_support/test_case.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: testing.rb

File
testing.rb
Path: | activesupport/lib/active_support/testing.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • active_support/testing/default


File: default.rb

File
default.rb
Path: | activesupport/lib/active_support/testing/default.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: time_zone.rb

File
time_zone.rb
Path: | activesupport/lib/active_support/values/time_zone.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

A value object representing a time zone. A time zone is simply a named offset (in seconds) from GMT. Note that two time zone objects are only equivalent if they have both the same offset, and the same name.

A TimeZone instance may be used to convert a Time value to the corresponding time zone.

The class also includes all, which returns a list of all TimeZone objects.


File: vendor.rb

File
vendor.rb
Path: | activesupport/lib/active_support/vendor.rb
Modified: | Sun Mar 02 11:08:50 -0700 2008

Prefer gems to the bundled libs.

Required Files
  • rubygems


File: blankslate.rb

File
blankslate.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008


File: builder.rb

File
builder.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • builder/xmlmarkup
  • builder/xmlevents


File: blankslate.rb

File
blankslate.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • blankslate


File: css.rb

File
css.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • builder/blankslate


File: xchar.rb

File
xchar.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

The XChar library is provided courtesy of Sam Ruby (See intertwingly.net/stories/2005/09/28/xchar.rb)


File: xmlbase.rb

File
xmlbase.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • builder/blankslate
  • builder/xchar


File: xmlevents.rb

File
xmlevents.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • builder/xmlmarkup


File: xmlmarkup.rb

File
xmlmarkup.rb
Path: | activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

Required Files
  • builder/xmlbase


File: xmlsimple.rb

File
xmlsimple.rb
Path: | activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb
Modified: | Sun Mar 02 11:08:49 -0700 2008

XmlSimple

Author: | Maik Schmidt <contact@maik-schmidt.de>
Copyright: | Copyright (c) 2003-2006 Maik Schmidt
License: | Distributes under the same terms as Ruby.
Required Files
  • rexml/document
  • stringio


File: version.rb

File
version.rb
Path: | activesupport/lib/active_support/version.rb
Modified: | Sun Mar 02 11:08:50 -0700 2008


File: whiny_nil.rb

File
whiny_nil.rb
Path: | activesupport/lib/active_support/whiny_nil.rb
Modified: | Sun Mar 02 11:08:50 -0700 2008

Extensions to nil which allow for more helpful error messages for people who are new to rails.

The aim is to ensure that when users pass nil to methods where that isn‘t appropriate, instead of NoMethodError and the name of some method used by the framework users will see a message explaining what type of object was expected.


File: CHANGELOG

File
CHANGELOG
Path: | activesupport/CHANGELOG
Modified: | Sun Mar 02 11:08:48 -0700 2008

SVN

  • Ruby 1.9 compatibility. 1689, 10466, 10468 [Cheah Chu Yeow, Pratik Naik, Jeremy Kemper]
  • TimeZone#to_s uses UTC rather than GMT. 1689 [Cheah Chu Yeow]
  • Refactor of Hash#symbolize_keys! to use Hash#replace. Closes 10420 [ReinH]
  • Fix HashWithIndifferentAccess#to_options! so it doesn‘t clear the options hash. Closes 10419 [ReinH]

*2.0.1* (December 7th, 2007)

  • Added Array#from and Array#to that behaves just from String#from and String#to [DHH]
  • Fix that empty collections should be treated as empty arrays regardless of whitespace for Hash#from_xml 10255 [adamj]
  • Time#time_with_datetime_fallback, Time#to_datetime, Date#to_datetime and String#to_datetime honor Ruby‘s default calendar reform setting. 10201 [Geoff Buesing]
  • Change Time and DateTime end_of_month to return last second of month instead of beginning of last day of month. Closes 10200 [Geoff Buesing]
  • Speedup String#blank? [Jeremy Kemper, Koz]
  • Add documentation for Hash#diff. Closes 9306 [Tarmo Tänav]
  • Add new superclass_delegating_accessors. Similar to class inheritable attributes but with subtly different semantics. [Koz, Tarmo Tänav]
  • Change JSON to encode %w(< > &) as 4 digit hex codes to be in compliance with the JSON spec. Closes 9975 [Josh Peek, Cheah Chu Yeow, Tim Pope]
  • Fix JSON encoding/decoding bugs dealing with /’s. Closes 9990 [Rick, theamazingrando]
  • Introduce a base class for all test cases used by rails applications. ActiveSupport::TestCase [Koz]

    The intention is to use this to reduce the amount of monkeypatching / overriding that is done to test/unit‘s classes.

  • Document Enumerable and Hash to_json. 9970 [Cheah Chu Yeow]
  • Hash#to_xml handles symbol values. 9954 [Assaf]
  • Hash#symbolize_keys behaves well with integer keys. 9890 [PotatoSalad]
  • Multibyte: String#slice supports regexp argument. 9646 [yob]
  • object.duplicable? returns true if object.dup is safe. False for nil, true, false, symbols, and numbers; true otherwise. 9333 [sur]
  • Time, Date and DateTime advance accept :weeks option. 9866 [Geoff Buesing]
  • Fix Time#years_ago and years_since from leap days. 9865 [Geoff Buesing]
  • Time and DateTime#advance accept :hours, :minutes, and :seconds options. 9825 [Geoff Buesing]
  • Fix Date#years_ago and years_since from leap days. 9864 [Geoff Buesing]
  • Refactor Time and Date#months_since and months_ago to use advance. 9863 [Geoff Buesing]
  • Rebundle Builder 2.1.2 but prefer a newer RubyGem if available. [Jeremy Kemper]
  • Add Range#overlaps?(range), Range#include?(range), and Range#step without a block. [brandon]
  • Correct BufferedLogger#level? checks. 9806 [wildchild, Johan Sorensen]
  • String#to_xs uses Eric Wong‘s fast_xs extension, if available, for Builder speedup. bogomips.org/fast_xs/ [Jeremy Kemper]
  • Introduce BasicObject as Builder::BlankSlate for Ruby 1.9 forward compatibility. [Jeremy Kemper]
  • Unbundle Builder in favor of a gem dependency. [Jeremy Kemper]
  • Disambiguate Time, Date, and DateTime#to_json formatting. 9750 [Geoff Buesing, Cheah Chu Yeow]
  • Hash#to_json takes :only or :except options to specific or omit certain hash keys. Enumerable#to_json passes through its options to each element. 9751 [Cheah Chu Yeow]
  • BufferedLogger#auto_flushing = N flushes the log every N messages. Buffers with an array instead of string. Disabling auto_flushing still flushes when the buffer hits a maximum size, as a failsafe against memory-gobbling. [Jeremy Kemper]
  • Fixed Date#xmlschema for dates outside the range of what can be created with Time 9744 [Geoff Buesing]
  • Fixed that La Paz was included in -25200 and -14400 offsets when it should only be in -14400 9735 [bermi]
  • Fixed JSON encoding to use quoted keys according to the JSON standard. 8762 [choonkat, Cheah Chu Yeow]
  • Alias Object#send to send! for Ruby 1.9 forward compatibility. [Jeremy Kemper]
  • Backport Object#instance_variable_defined? for Ruby < 1.8.6. [Jeremy Kemper]
  • BufferedLogger#add converts the message to a string. 9702, 9724 [eigentone, DrMark, tomafro]
  • Added ActiveSupport::BufferedLogger as a duck-typing alternative (albeit with no formatter) to the Ruby Logger, which provides a very nice speed bump (inspired by Ezra‘s buffered logger) [DHH]
  • Object#instance_exec produces fewer garbage methods. [Mauricio Fernandez]
  • Decode json strings as Dates/Times if they‘re using a YAML-compatible format. Closes 9614 [Rick]
  • Fixed cache_page to use the request url instead of the routing options when picking a save path. 8614 [Josh Peek]
  • Object.subclasses_of includes anonymous subclasses. [Jeremy Kemper]
  • Fixed that pluralizing an empty string should return the same empty string, not "s". 7720 [Josh Peek]
  • Added call to inspect on non-string classes for the logger 8533 [codahale]
  • Deprecation: remove deprecated :mday option from Time, Date, and DateTime#change. [Jeremy Kemper]
  • Fix JSON decoder with nested quotes and commas. 9579 [zdennis]
  • Hash#to_xml doesn‘t double-unescape. 8806 [Ezran]
  • Added Array#rand 9170 [Norbert Crombach]. Examples:
      [].rand       # => nil
  ['a'].rand    # => 'a'
  [1,2,3].rand  # => 1 or 2 or 3
  • Deprecation: removed Reloadable. [Jeremy Kemper]
  • Make the utf-handler return the correct value for non-matching regular expressions. Closes 9049 [manfred]
  • Add ljust, rjust and center to utf8-handler. Closes 9165 [manfred]
  • Fix Time#advance bug when trying to advance a year from leap day. Closes 8655 [gbuesing]
  • Add support for []= on ActiveSupport::Multibyte::Chars. Closes 9142. [ewan, manfred]
  • Added Array#extract_options! to encapsulate the pattern of getting an options hash out of a variable number of parameters. 8759 [Norbert Crombach]
  • Let alias_attribute work with attributes with initial capital letters (legacy columns etc). Closes 8596 [mpalmer]
  • Added Hash#except which is the inverse of Hash#slice — return the hash except the keys that are specified [DHH]
  • Added support for pluralization with a different starting letter than the singular version (cow/kine) 4929 [norri_b/hasmanyjosh]
  • Demote Hash#to_xml to use XmlSimple#xml_in_string so it can‘t read files or stdin. 8453 [candlerb, Jeremy Kemper]
  • Backport clean_logger changes to support ruby 1.8.2 [mislav]
  • Added proper handling of arrays 8537 [hasmanyjosh]

    Before:

      Hash.from_xml '<images></images>'
  # => {:images => nil}

  Hash.from_xml '<images><image>foo.jpg</image></images>'
  # => {:images => {:image => "foo.jpg"}}

  Hash.from_xml '<images><image>foo.jpg</image><image>bar.jpg</image></images>'
  # => {:images => {:image => ["foo.jpg", "bar.jpg"]}}

    After:

      Hash.from_xml '<images type="array"></images>'
  # => {:images => []}

  Hash.from_xml '<images type="array"><image>foo.jpg</image></images>'
  # => {:images => ["foo.jpg"]}

  Hash.from_xml '<images type="array"><image>foo.jpg</image><image>bar.jpg</image></images>'
  # => {:images => ["foo.jpg", "bar.jpg"]}
  • Improve Time and Date test coverage. 8646 [Josh Peek]
  • Add Date#since, ago, beginning_of_day, and end_of_day. Date + seconds works now. 8575 [Geoff Buesing]
  • String#to_time overflows to DateTime. Add String#to_datetime. 8572 [Geoff Buesing]
  • Date.yesterday and .tomorrow. 8571 [Geoff Buesing]
  • Readable Date and DateTime#inspect. 8570 [Geoff Buesing]
  • Move common DateTime calculations to Date. 8536 [Geoff Buesing]
  • Added Date#change (like Time#change) [DHH]
  • DateTime#to_time converts to Time unless out of range. 8512 [Geoff Buesing]
  • Date#to_datetime, to_s(:rfc822). 8512 [Geoff Buesing]
  • Time durations use since instead of + for accuracy. 8513 [Geoff Buesing]
  • escape <’s and >’s in JSON strings. 8371 [Rick]
  • Inflections: MatrixTest -> MatrixTests instead of MatricesTest. 8496 [jbwiv]
  • Multibyte strings respond_to the String methods they proxy so they can be duck-typed. 6549 [Tuxie]
  • Array#to_xml yields the builder just like Hash and ActiveRecord::Base. 8472 [seth]
  • Date, Time, and DateTime support formatting blocks in addition to strftime strings. Introduce :long_ordinal format, e.g. "February 21st, 2005". 8191 [Coda Hale]
  • Document Object#blank?. 6491 [Chris Mear]
  • Date, Time, and DateTime#to_json. 8399 [wycats]
  • Simplify API of assert_difference by passing in an expression that is evaluated before and after the passed in block. See documenation for examples of new API. [Marcel Molina Jr.]
  • Added assert_difference and assert_no_difference to test/unit assertions [Tobias Luetke]
  • Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]
  • Added parsing of file type in Hash.xml_in so you can easily do file uploads with base64 from an API [DHH]
      <person>
    <name>David</name>
    <avatar type="file" name="me.jpg" content_type="image/jpg">R0lGODlhkACZAPUAAM5lcfjrtMQCG=\n</avatar>
  </person>

    …becomes:

      attributes = { :person => { :name => "David", :avatar => #<StringIO> } }
  attributes[:person][:avatar].content_type      # => "image/jpg"
  attributes[:person][:avatar].original_filename # => "me.jpg"
  attributes[:person][:avatar].read # => binary data of the file

    Which is duck-type compatible with the files that you get when doing multipart uploads through HTML.

  • Improved multibyte performance by relying less on exception raising 8159 [Blaine]
  • Use XSD-compatible type names for Hash#to_xml and make the converters extendable 8047 [Tim Pope]
  • Added yielding of builder in Hash#to_xml [DHH]
  • Hash#with_indifferent_access now also converts hashes kept in arrays to indifferent access (makes it easier to treat HTML and XML parameters the same) [DHH]
  • Hash#to_xml supports YAML attributes. 7502 [jonathan]
  • Refactor ActiveSupport::JSON to be less obtuse. Add support for JSON decoding by way of Syck with ActiveSupport::JSON.decode(json_string). Prevent hash keys that are JavaScript reserved words from being unquoted during encoding. [Sam Stephenson]
  • alias_method_chain preserves the original method‘s visibility. 7854 [Jonathan Viney]
  • Update Dependencies to ignore constants inherited from ancestors. Closes 6951. [Nicholas Seckar]
  • Array#to_query preserves its ordering. 7756 [Greg Spurrier]
  • Out-of-range Time calculations transparently overflow to DateTime. Introduce Time#to_datetime. 7706, 7715 [Geoff Buesing]
  • DateTime calculations analogous to the Date and Time extensions. 7693 [Geoff Buesing]
  • Give DateTime correct .to_s implementations, lets it play nice with ActiveRecord quoting. 7649 [Geoff Buesing]
  • Add File.atomic_write, allows you to write large files in an atomic manner, preventing users from seeing half written files. [Koz]
  • Allow users to provide custom formatters to Logger. [aeden]
  • Hash#to_query CGI-escapes its keys. [Jeremy Kemper]
  • Optimize Class Inheritable Attributes so that unnecessary hashes are not created. Closes 7472 [Bruce Perens]
  • :db format for Date#to_s [Jeremy Kemper]
      Date.new(2007, 1, 27).to_s(:db) # => '2007-01-27'
  • Added :instance_writer option to mattr_writer/accessor, cattr_writer/accessor, and class_inheritable_writer to skip the creation of the instance writer. [Rick]
  • Added Hash#to_query to turn a hash of values into a form-encoded query string [Nicholas Seckar]
  • Increase test coverage for subclasses_of. Closes 7335. [Roman2K, Nicholas Seckar]
  • Remove unused code from Duration#inspect. Closes 7180. [Rich Collins]
  • Added test coverage for Inflector.inflections.clear. Closes 7179. [Rich Collins]
  • ActiveSupport::Multibyte::Handlers::UTF8Handler should raise when a range and an integer are passed in (just like the native implementation). Closes 7176 [Rich Collins]
  • A couple extra tests for classify. Closes 7273. [Josh Susser]
  • Better docs for Object extensions [zackchandler, Jamis Buck]
  • Fix that Dates couldn‘t be subtracted from Dates after [5940]. [Sam Stephenson]
  • Add Object#acts_like? and Time#acts_like_time? and Date#acts_like_date? to facilitate duck-typing. [Jamis Buck]
  • Make 1.months and friends accurate by introducing a Duration class. 6835 [eventualbuddha]

*1.4.2* (March 12th, 2007)

  • Ruby 1.8.6 and 1.9 define private Time#to_date and to_datetime; make them

public for compatibility. [Jeremy Kemper]

  • Deprecation: warn on stderr if RAILS_DEFAULT_LOGGER isn‘t set yet. [Jeremy Kemper]

*1.4.1* (February 5th, 2007)

  • Optimize Class Inheritable Attributes so that unnecessary hashes are not created. Closes 7472 [Bruce Perens]
  • Added :instance_writer option to mattr_writer/accessor, cattr_writer/accessor, and class_inheritable_writer to skip the creation of the instance writer. [Rick]
  • Full test coverage for Inflector. 7228 [Dan Kubb]

*1.4.0* (January 16th, 2007)

  • Document Inflector.ordinalize and merge docs from String inflections. 7023 [smeade]
  • Unbundle flexmock. [Jeremy Kemper]
  • Fix Dependencies.autoloaded? to ignore anonymous modules. Closes 6561. [Nicholas Seckar]
  • Update load once paths to prevent nested once constants from being detected and claimed by an external non-once load. [Nicholas Seckar]
  • Deprecation: silence warnings when reporting test errors. [Jeremy Kemper]
  • Hash#slice(*keys) returns a new hash with only the given keys. slice! replaces the hash with only the given keys. Works with HashWithIndifferentAccess also. [Jeremy Kemper]
  • HashWithIndifferentAccess#to_hash converts to a Hash with String keys and the same default value. [Jeremy Kemper]
  • Fix remove_constant to correctly handle constant names of the form "::A::…". References 6720. [Nicholas Seckar]
  • Fixed Array#to_xml when it contains a series of hashes (each piece would get its own XML declaration) 6610 [thkarcher/cyu]
  • Added Time#to_s(:time) which will just return H:M, like 17:44 [DHH]
  • Add Module#attr_accessor_with_default to initialize value of attribute before setting it. Closes 6538. [Stuart Halloway, Marcel Molina Jr.]
  • Hash#to_xml handles keys with the same name as Kernel methods. 6613 [Catfish]
  • Added Time#end_of_day to get 23:59:59 of that day [DHH]
  • Don‘t quote hash keys in Hash#to_json if they‘re valid JavaScript identifiers. Disable this with ActiveSupport::JSON.unquote_hash_key_identifiers = false if you need strict JSON compliance. [Sam Stephenson]
  • Lazily load the Unicode Database in the UTF-8 Handler [Rick Olson]
  • Update dependencies to delete partially loaded constants. [Nicholas Seckar]
  • Fix unicode JSON regexp for Onigurama compatibility. 6494 [whitley]
  • update XmlSimple to 1.0.10. Closes 6532. [nicksieger]
  • Update dependencies to allow constants to be defined alongside their siblings. A common case for this is AR model classes with STI; user.rb might define User, Administrator and Guest for example. [Nicholas Seckar]
  • next_week respects DST changes. 6483, 5617, 2353, 2509, 4551 [marclove, rabiedenharn, rails@roetzel.de, jsolson@damogran.org, drbrain@segment7.net]
  • Expose methods added to Enumerable in the documentation, such as group_by. Closes 6170. [sergeykojin@gmail.com, Marcel Molina Jr.]
  • Ensure Chars#tidy_bytes only tidies broken bytes. Closes 6397 [Manfred Stienstra]
  • Add ‘unloadable’, a method used to mark any constant as requiring an unload after each request. [Nicholas Seckar]
  • Make core_ext/string/access.rb multibyte safe. Closes 6388 [Manfred Stienstra]
  • Make String#chars slicing behaviour consistent with String. Closes 6387 [Manfred Stienstra]
  • Pull in latest multibyte patch. Closes 6346 [Manfred Stienstra]
  • Add ActiveSupport::Multibyte. Provides String#chars which lets you deal with strings as a sequence of chars, not of bytes. Closes 6242 [Julian Tarkhanov, Manfred Stienstra, Thijs van der Vossen & Jan Behrens]
  • Fix issue with class_inheritable_accessor saving updates to the parent class when initialized with an Array or Hash [mojombo]
  • Hash#to_xml supports Bignum and BigDecimal. 6313 [edibiase]
  • Don‘t undefine class in OptionMerger [Rick]
  • Hash.create_from_xml has been renamed to Hash.from_xml, alias will exist until Rails 2.0 [DHH]
  • alias_method_chain works with accessor= methods also. 6153 [Caio Chassot]
  • Fix loadable_constants_for_path to handle load paths that do not end with a slash. [Nicholas Seckar]
  • Fix logic error in determining what was loaded by a given file. Closes 6039. [Nicholas Seckar]
  • Equate Kernel.const_missing with Object.const_missing. Fixes 5988. [Nicholas Seckar]
  • Add ApplicationController special case to Dependencies. [Nicholas Seckar]
  • Don‘t pad remaining places with in_groups_of if specified padding value is false. [Marcel Molina Jr.]
  • Fix cases where empty xml nodes weren‘t being translated to nil in Hash.create_from_xml [Rick Olso n]

    <written-on type="date"></written-on> # => { :type => ‘date’ } # WRONG <written-on type="date"></written-on> # => nil # RIGHT

  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Inflections: don‘t singularize -ies plurals. [foamdino@gmail.com, Mark Van Holstyn]
  • Update Initializer to use load_once_paths to avoid plugin reloading. References 5852. [Nicholas Seckar]
  • Use Array#assoc in ActiveSupport::OrderedHash. [Mauricio Fernandez]
  • Greatly increased performance of String.to_json, which speeds up RJS considerably on large pages, fixes 3473 [Shugo Maeda]
  • Detect missing_constants calls from removed modules and fail accordingly. [Nicholas Seckar]
  • Stop using defined? in Dependencies.qualified_const_defined? since defined? may invoke const_missing. [Nicholas Seckar]
  • Dependencies can autoload directories of nested classes. [Jeremy Kemper]
      Example:
    invoice.rb            class Invoice
    invoice/lineitem.rb   class Invoice::Lineitem
  • Add Deprecation.silence so that Reloadable does not scold itself. [Nicholas Seckar]
  • Add debugging logging to Dependencies. Currently can be enabled with Dependencies.log_activity = true; adding to Initializer and documenting is forthcoming. [Nicholas Seckar]
  • Replace Reloadable with improvements to the Dependencies mechanism. [Nicholas Seckar]
  • DateTime#to_time gives hour/minute/second resolution. 5747 [jon.evans@pobox.com]
  • attr_internal to support namespacing and deprecation. Like attr_* except backed by internally-named instance variable. Set attr_internal_naming_format to change the format from the default ’@_%s’. [Jeremy Kemper]
      # def foo()   @foo__rofl      end
  # def foo=(v) @foo__rofl = v  end
  self.attr_internal_naming_format = '@%s__rofl'
  attr_internal :foo
  • Raise fully qualified names upon name errors. 5533 [lars@pinds.com, Nicholas Seckar]
  • Add extention to obtain the missing constant from NameError instances. [Nicholas Seckar]
  • Thoroughly document inflections. 5700 [petermichaux@gmail.com]
  • Added Module#alias_attribute [Jamis/DHH]. Example:
      class Content < ActiveRecord::Base
    # has a title attribute
  end

  class Email < ActiveRecord::Base
    alias_attribute :subject, :title
  end

  e = Email.find(1)
  e.title    # => "Superstars"
  e.subject  # => "Superstars"
  e.subject? # => true
  e.subject = "Megastars"
  e.title    # => "Megastars"
  • Deprecation: easier to work with warning behavior as procs; default behaviors for each environment so users needn‘t update env.rb; and testing pleasure with assert_deprecated, assert_not_deprecated. [Jeremy Kemper] By default, test prints to $stderr, dev logs, production ignores. Provide your own per-environment in e.g. config/environments/development.rb:
      ActiveSupport::Deprecation.behavior = Proc.new { |message| raise message }
  • First cut of the Rails Deprecation system. [Koz]
  • Strip boolean XML content before checking for ‘true’ [Rick Olson]
  • Customize default BigDecimal formatting. References 5672 [dave@pragprog.com]
  • Correctly convert <foo nil="true"> to nil when using Hash.create_from_xml. [Rick]
  • Optional identity for Enumerable#sum defaults to zero. 5657 [gensym@mac.com]
  • HashWithIndifferentAccess shouldn‘t confuse false and nil. 5601 [shugo@ruby-lang.org]
  • Fixed HashWithIndifferentAccess#default 5586 [chris@seagul.co.uk]
  • More compatible Hash.create_from_xml. 5523 [nunemaker@gmail.com]
  • Added Enumerable#sum for calculating a sum from the elements [DHH, jonathan@daikini.com]. Examples:
      [1, 2, 3].sum
  payments.sum { |p| p.price * p.tax_rate }
  payments.sum(&:price)

    This is instead of payments.inject(0) { |sum, p| sum + p.price }

  • Correct and clarify Array#to_sentence docs. 5458 [brad@madriska.com]
  • alias_method_chain preserves method punctuation so foo, foo?, and foo! may be chained with the same feature. [Jeremy Kemper]
      Example:
    alias_method_chain :save!, :validation
  is equivalent to
    alias_method :save_without_validation!, :save!
    alias_method :save!, :save_with_validation!
  • Enhance Symbol#to_proc so it works with list objects, such as multi-dimensional arrays. Closes 5295 [nov@yo.rim.or.jp]. Example:
      {1 => "one", 2 => "two", 3 => "three"}.sort_by(&:first).map(&:last)
  #=> ["one", "two", "three"]
  • Added Hash.create_from_xml(string) which will create a hash from a XML string and even typecast if possible [DHH]. Example:
      Hash.create_from_xml <<-EOT
    <note>
      <title>This is a note</title>
      <created-at type="date">2004-10-10</created-at>
    </note>
  EOT

    …would return:

      { :note => { :title => "This is a note", :created_at => Date.new(2004, 10, 10) } }
  • Added Jim Weirich‘s excellent FlexMock class to vendor (Copyright 2003, 2004 by Jim Weirich (jim@weriichhouse.org)) — it‘s not automatically required, though, so require ‘flexmock’ is still necessary [DHH]
  • Fixed that Module#alias_method_chain should work with both foo? foo! and foo at the same time 4954 [anna@wota.jp]
  • to_xml fixes, features, and speedup: introduce :dasherize option that converts updated_at to updated-at if true (the existing default); binary columns get encoding="base64" attribute; nil values get nil="true" attribute to distinguish empty values; add type information for float columns; allow arbitrarily deep :include; include SQL type information as the type attribute. 4989 [Blair Zajac <blair@orcaware.com>]
  • Add OrderedHash#values. [Sam Stephenson]
  • Added Array#to_s(:db) that‘ll produce a comma-separated list of ids [DHH]. Example:
      Purchase.find(:all, :conditions => "product_id IN (#{shops.products.to_s(:db)})"
  • Normalize classify‘s argument to a String so that it plays nice with Symbols. [Marcel Molina Jr.]
  • Strip out leading schema name in classify. References 5139. [schoenm@earthlink.net]
  • Remove Enumerable#first_match since break(value) handles the use case well enough. [Nicholas Seckar]

    Enumerable#first_match was like detect, but instead of returning the matching element, the yielded value returned. For example:

      user_xml = adapters(:from => User, :to => Xml).first_match do |adapter|
    adapter.adapt @user
  end

    But this is just as easily done with:

      user_xml = adapters(:from => User, :to => Xml).each do
    break adapter.adapt(@user)
  end
  • Make Array#in_groups_of just return the grouped collection if a block isn‘t given. [Marcel Molina Jr.]
  • Don‘t destroy a HashWithIndifferentAccess if symbolize_keys! or stringify_keys! is called on it. Closes 5076. [Marcel Molina Jr., guy.naor@famundo.com]
  • Document Module::delegate. 5002 [pergesu@gmail.com]
  • Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
  • Strip out punctuation on predicates or bang methods being aliased with alias_method_chain since target?_without_feature is not a valid method name. Add tests for Module#alias_method_chain. [Marcel Molina Jr.]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Allow default options in with_options to be overridden. Closes 4480. [murphy@cYcnus.de]
  • Added Module#alias_method_chain [Jamis Buck]
  • Updated to Builder 2.0 [DHH]
  • Add Array#split for dividing arrays into one or more subarrays by value or block. [Sam Stephenson]

*1.3.1* (April 6th, 2006)

  • Clean paths inside of exception messages and traces. [Nicholas Seckar]
  • Add Pathname.clean_within for cleaning all the paths inside of a string. [Nicholas Seckar]
  • provide an empty Dependencies::LoadingModule.load which prints deprecation warnings. Lets 1.0 applications function with .13-style environment.rb.

*1.3.0* (March 27th, 2006)

  • When possible, avoid incorrectly obtaining constants from parent modules. Fixes 4221. [Nicholas Seckar]
  • Add more tests for dependencies; refactor existing cases. [Nicholas Seckar]
  • Move Module#parent and Module#as_load_path into core_ext. Add Module#parent. [Nicholas Seckar]
  • Add CachingTools::HashCaching to simplify the creation of nested, autofilling hashes. [Nicholas Seckar]
  • Remove a hack intended to avoid unloading the same class twice, but which would not work anyways. [Nicholas Seckar]
  • Update Object.subclasses_of to locate nested classes. This affects Object.remove_subclasses_of in that nested classes will now be unloaded. [Nicholas Seckar]
  • Update Object.remove_subclasses_of to use Class.remove_class, reducing duplication. [Nicholas Seckar]
  • Added Fixnum#seconds for consistency, so you can say 5.minutes + 30.seconds instead of 5.minutes + 30 4389 [François Beausoleil]
  • Added option to String#camelize to generate lower-cased camel case by passing in :lower, like "super_man".camelize(:lower) # => "superMan" [DHH]
  • Added Hash#diff to show the difference between two hashes [Chris McGrath]
  • Added Time#advance to do precise time time calculations for cases where a month being approximated to 30 days won‘t do 1860 [Rick Olson]
  • Enhance Inflector.underscore to convert ’-’ into ‘_’ (as the inverse of Inflector.dasherize) [Jamis Buck]
  • Switched to_xml to use the xml schema format for datetimes. This allows the encoding of time zones and should improve operability. [Koz]
  • Added a note to the documentation for the Date related Numeric extensions to indicate that they‘re

approximations and shouldn‘t be used for critical calculations. [Koz]

  • Added Hash#to_xml and Array#to_xml that makes it much easier to produce XML from basic structures [DHH]. Examples:
      { :name => "David", :street_name => "Paulina", :age => 26, :moved_on => Date.new(2005, 11, 15) }.to_xml

    …returns:

        <person>
      <street-name>Paulina</street-name>
      <name>David</name>
      <age type="integer">26</age>
      <moved-on type="date">2005-11-15</moved-on>
    </person>
  • Moved Jim Weirich‘s wonderful Builder from Action Pack to Active Support (it‘s simply too useful to be stuck in AP) [DHH]
  • Fixed that Array#to_sentence will return "" on an empty array instead of ", and" 3842, 4031 [rubyonrails@beautifulpixel.com]
  • Add Enumerable#group_by for grouping collections based on the result of some block. Useful, for example, for grouping records by date.

    ex.

       latest_transcripts.group_by(&:day).each do |day, transcripts|
     p "#{day} -> #{transcripts.map(&:class) * ', '}"
   end
   "2006-03-01 -> Transcript"
   "2006-02-28 -> Transcript"
   "2006-02-27 -> Transcript, Transcript"
   "2006-02-26 -> Transcript, Transcript"

    Add Array#in_groups_of, for iterating over an array in groups of a certain size.

    ex.

       %w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g}
   ["1", "2", "3"]
   ["4", "5", "6"]
   ["7", nil, nil]

    [Marcel Molina Jr., Sam Stephenson]

  • Added Kernel#daemonize to turn the current process into a daemon that can be killed with a TERM signal [DHH]
  • Add ‘around’ methods to Logger, to make it easy to log before and after messages for a given block as requested in 3809. [Michael Koziarski] Example:

    logger.around_info("Start rendering component (#{options.inspect}): ",

                       "\n\nEnd of component rendering") { yield }
  • Added Time#beginning_of_quarter 3607 [cohen.jeff@gmail.com]
  • Fix Object.subclasses_of to only return currently defined objects [Jonathan Viney <jonathan@bluewire.net.nz>]
  • Fix constantize to properly handle names beginning with ’::’. [Nicholas Seckar]
  • Make String#last return the string instead of nil when it is shorter than the limit [Scott Barron].
  • Added delegation support to Module that allows multiple delegations at once (unlike Forwardable in the stdlib) [DHH]. Example:
      class Account < ActiveRecord::Base
    has_one :subscription
    delegate :free?, :paying?, :to => :subscription
    delegate :overdue?, :to => "subscription.last_payment"
  end

  account.free?    # => account.subscription.free?
  account.overdue? # => account.subscription.last_payment.overdue?
  • Fix Reloadable to handle the case where a class that has been ‘removed’ has not yet been garbage collected. [Nicholas Seckar]
  • Don‘t allow Reloadable to be included into Modules.
  • Remove LoadingModule. [Nicholas Seckar]
  • Add documentation for Reloadable::Subclasses. [Nicholas Seckar]
  • Add Reloadable::Subclasses which handles the common case where a base class should not be reloaded, but its subclasses should be. [Nicholas Seckar]
  • Further improvements to reloading code [Nicholas Seckar, Trevor Squires]
    • All classes/modules which include Reloadable can define reloadable? for fine grained control of reloading
    • Class.remove_class uses Module#parent to access the parent module
    • Class.remove_class expanded to handle multiple classes in a single call
    • LoadingModule.clear! has been removed as it is no longer required
    • Module#remove_classes_including has been removed in favor of Reloadable.reloadable_classes
  • Added reusable reloading support through the inclusion of the Relodable module that all subclasses of ActiveRecord::Base, ActiveRecord::Observer, ActiveController::Base, and ActionMailer::Base automatically gets. This means that these classes will be reloaded by the dispatcher when Dependencies.mechanism = :load. You can make your own models reloadable easily:
      class Setting
    include Reloadable
  end

    Reloading a class is done by removing its constant which will cause it to be loaded again on the next reference. [DHH]

  • Added auto-loading support for classes in modules, so Conductor::Migration will look for conductor/migration.rb and Conductor::Database::Settings will look for conductor/database/settings.rb [Nicholas Seckar]
  • Add Object#instance_exec, like instance_eval but passes its arguments to the block. (Active Support will not override the Ruby 1.9 implementation of this method.) [Sam Stephenson]
  • Add Proc#bind(object) for changing a proc or block‘s self by returning a Method bound to the given object. Based on why the lucky stiff‘s "cloaker" method. [Sam Stephenson]
  • Fix merge and dup for hashes with indifferent access 3404 [kenneth.miller@bitfield.net]
  • Fix the requires in option_merger_test to unbreak AS tests. [Sam Stephenson]
  • Make HashWithIndifferentAccess#update behave like Hash#update by returning the hash. 3419, 3425 [asnem@student.ethz.ch, JanPrill@blauton.de, Marcel Molina Jr.]
  • Add ActiveSupport::JSON and Object#to_json for converting Ruby objects to JSON strings. [Sam Stephenson]
  • Add Object#with_options for DRYing up multiple calls to methods having shared options. [Sam Stephenson] Example:

    ActionController::Routing::Routes.draw do |map|

      # Account routes
  map.with_options(:controller => 'account') do |account|
    account.home   '',       :action => 'dashboard'
    account.signup 'signup', :action => 'new'
    account.logout 'logout', :action => 'logout'
  end

    end

  • Introduce Dependencies.warnings_on_first_load setting. If true, enables warnings on first load of a require_dependency. Otherwise, loads without warnings. Disabled (set to false) by default. [Jeremy Kemper]
  • Active Support is warnings-safe. 1792 [Eric Hodel]
  • Introduce enable_warnings counterpart to silence_warnings. Turn warnings on when loading a file for the first time if Dependencies.mechanism == :load. Common mistakes such as redefined methods will print warnings to stderr. [Jeremy Kemper]
  • Add Symbol#to_proc, which allows for, e.g. [:foo, :bar].map(&:to_s). [Marcel Molina Jr.]
  • Added the following methods [Marcel Molina Jr., Sam Stephenson]:
    • Object#copy_instance_variables_from(object) to copy instance variables from one object to another
    • Object#extended_by to get an instance‘s included/extended modules
    • Object#extend_with_included_modules_from(object) to extend an instance with the modules from another instance

*1.2.5* (December 13th, 2005)

  • Become part of Rails 1.0
  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]

*1.2.3* (November 7th, 2005)

  • Change Inflector#constantize to use eval instead of const_get. [Nicholas Seckar]
  • Fix const_missing handler to ignore the trailing ’.rb’ on files when comparing paths. [Nicholas Seckar]
  • Define kernel.rb methods in "class Object" instead of "module Kernel" to work around a Windows peculiarity [Sam Stephenson]
  • Fix broken tests caused by incomplete loading of active support. [Nicholas Seckar]
  • Fix status pluralization bug so status_codes doesn‘t get pluralized as statuses_code. 2758 [keithm@infused.org]
  • Added Kernel#silence_stderr to silence stderr for the duration of the given block [Sam Stephenson]
  • Changed Kernel#` to print a message to stderr (like Unix) instead of raising Errno::ENOENT on Win32 [Sam Stephenson]
  • Changed 0.blank? to false rather than true since it violates everyone‘s expectation of blankness. 2518, 2705 [rails@jeffcole.net]
  • When loading classes using const_missing, raise a NameError if and only if the file we tried to load was not present. [Nicholas Seckar]
  • Added petabytes and exebytes to numeric extensions 2397 [timct@mac.com]
  • Added Time#end_of_month to accompany Time#beginning_of_month 2514 [Jens-Christian Fischer]

*1.2.2* (October 26th, 2005)

  • Set Logger.silencer = false to disable Logger#silence. Useful for debugging fixtures.
  • Add title case method to String to do, e.g., ‘action_web_service’.titlecase # => ‘Action Web Service’. [Marcel Molina Jr.]

*1.2.1* (October 19th, 2005)

  • Classify generated routing code as framework code to avoid appearing in application traces. [Nicholas Seckar]
  • Show all framework frames in the framework trace. [Nicholas Seckar]

*1.2.0* (October 16th, 2005)

  • Update Exception extension to show the first few framework frames in an application trace. [Nicholas Seckar]
  • Added Exception extension to provide support for clean backtraces. [Nicholas Seckar]
  • Updated whiny nil to be more concise and useful. [Nicholas Seckar]
  • Added Enumerable#first_match [Nicholas Seckar]
  • Fixed that Time#change should also reset usec when also resetting minutes 2459 [ikeda@dream.big.or.jp]
  • Fix Logger compatibility for distributions that don‘t keep Ruby and its standard library in sync.
  • Replace ’%e’ from long and short time formats as Windows does not support it. 2344. [Tom Ward <tom@popdog.net>]
  • Added to_s(:db) to Range, so you can get "BETWEEN ‘2005-12-10’ AND ‘2005-12-12’" from Date.new(2005, 12, 10)..Date.new(2005, 12, 12) (and likewise with Times)
  • Moved require_library_or_gem into Kernel. 1992 [Michael Schuerig <michael@schuerig.de>]
  • Add :rfc822 as an option for Time#to_s (to get rfc822-formatted times)
  • Chain the const_missing hook to any previously existing hook so rails can play nicely with rake
  • Clean logger is compatible with both 1.8.2 and 1.8.3 Logger. 2263 [Michael Schuerig <michael@schuerig.de>]
  • Added native, faster implementations of .blank? for the core types 2286 [skae]
  • Fixed clean logger to work with Ruby 1.8.3 Logger class 2245
  • Fixed memory leak with Active Record classes when Dependencies.mechanism = :load 1704 [c.r.mcgrath@gmail.com]
  • Fixed Inflector.underscore for use with acronyms, so HTML becomes html instead of htm_l 2173 [k@v2studio.com]
  • Fixed dependencies related infinite recursion bug when a controller file does not contain a controller class. Closes 1760. [rcolli2@tampabay.rr.com]
  • Fixed inflections for status, quiz, move 2056 [deirdre@deirdre.net]
  • Added Hash#reverse_merge, Hash#reverse_merge!, and Hash#reverse_update to ease the use of default options
  • Added Array#to_sentence that‘ll turn [‘one’, ‘two’, ‘three’] into "one, two, and three" 2157 [m.stienstra@fngtps.com]
  • Added Kernel#silence_warnings to turn off warnings temporarily for the passed block
  • Added String#starts_with? and String#ends_with? 2118 [thijs@vandervossen.net]
  • Added easy extendability to the inflector through Inflector.inflections (using the Inflector::Inflections singleton class). Examples:
      Inflector.inflections do |inflect|
    inflect.plural /^(ox)$/i, '\1\2en'
    inflect.singular /^(ox)en/i, '\1'

    inflect.irregular 'octopus', 'octopi'

    inflect.uncountable "equipment"
  end
  • Added String#at, String#from, String#to, String#first, String#last in ActiveSupport::CoreExtensions::String::Access to ease access to individual characters and substrings in a string serving basically as human names for range access.
  • Make Time#last_month work when invoked on the 31st of a month.
  • Add Time.days_in_month, and make Time#next_month work when invoked on the 31st of a month
  • Fixed that Time#midnight would have a non-zero usec on some platforms 1836
  • Fixed inflections of "index/indices" 1766 [damn_pepe@gmail.com]
  • Added stripping of _id to String#humanize, so "employee_id" becomes "Employee" 1574 [Justin French]
  • Factor Fixnum and Bignum extensions into Integer extensions [Nicholas Seckar]
  • Hooked ordinalize into Fixnum and Bignum classes. [Nicholas Seckar, danp]
  • Added Fixnum#ordinalize to turn 1.ordinalize to "1st", 3.ordinalize to "3rd", and 10.ordinalize to "10th" and so on 1724 [paul@cnt.org]

*1.1.1* (11 July, 2005)

  • Added more efficient implementation of the development mode reset of classes 1638 [Chris McGrath]

*1.1.0* (6 July, 2005)

  • Fixed conflict with Glue gem 1606 [Rick Olson]
  • Added new rules to the Inflector to deal with more unusual plurals mouse/louse => mice/lice, information => information, ox => oxen, virus => viri, archive => archives 1571, 1583, 1490, 1599, 1608 [foamdino@gmail.com/others]
  • Fixed memory leak with Object#remove_subclasses_of, which inflicted a Rails application running in development mode with a ~20KB leak per request 1289 [c.r.mcgrath@gmail.com]
  • Made 1.year == 365.25.days to account for leap years. This allows you to do User.find(:all, :conditions => [‘birthday > ?’, 50.years.ago]) without losing a lot of days. 1488 [tuxie@dekadance.se]
  • Added an exception if calling id on nil to WhinyNil 584 [kevin-temp@writesoon.com]
  • Added Fix/Bignum#multiple_of? which returns true on 14.multiple_of?(7) and false on 16.multiple_of?(7) 1464 [Thomas Fuchs]
  • Added even? and odd? to work with Bignums in addition to Fixnums 1464 [Thomas Fuchs]
  • Fixed Time#at_beginning_of_week returned the next Monday instead of the previous one when called on a Sunday 1403 [jean.helou@gmail.com]
  • Increased the speed of indifferent hash access by using Hash#default. 1436 [Nicholas Seckar]
  • Added that " " is now also blank? (using strip if available)
  • Fixed Dependencies so all modules are able to load missing constants 1173 [Nicholas Seckar]
  • Fixed the Inflector to underscore strings containing numbers, so Area51Controller becomes area51_controller 1176 [Nicholas Seckar]
  • Fixed that HashWithIndifferentAccess stringified all keys including symbols, ints, objects, and arrays 1162 [Nicholas Seckar]
  • Fixed Time#last_year to go back in time, not forward 1278 [fabien@odilat.com]
  • Fixed the pluralization of analysis to analyses 1295 [seattle@rootimage.msu.edu]
  • Fixed that Time.local(2005,12).months_since(1) would raise "ArgumentError: argument out of range" 1311 [jhahn@niveon.com]
  • Added silencing to the default Logger class

*1.0.4* (19th April, 2005)

  • Fixed that in some circumstances controllers outside of modules may have hidden ones inside modules. For example, admin/content might have been hidden by /content. 1075 [Nicholas Seckar]
  • Fixed inflection of perspectives and similar words 1045 [thijs@vandervossen.net]
  • Added Fixnum#even? and Fixnum#odd?
  • Fixed problem with classes being required twice. Object#const_missing now uses require_dependency to load files. It used to use require_or_load which would cause models to be loaded twice, which was not good for validations and other class methods 971 [Nicholas Seckar]

*1.0.3* (27th March, 2005)

  • Fixed Inflector.pluralize to handle capitalized words 932 [Jeremy Kemper]
  • Added Object#suppress which allows you to make a saner choice around with exceptions to swallow 980. Example:
      suppress(ZeroDivisionError) { 1/0 }

    …instead of:

      1/0 rescue nil # BAD, EVIL, DIRTY.

*1.0.2* (22th March, 2005)

  • Added Kernel#returning — a Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
      def foo
    returning values = [] do
      values << 'bar'
      values << 'baz'
    end
  end

  foo # => ['bar', 'baz']

*1.0.1* (7th March, 2005)

  • Fixed Hash#indifferent_access to also deal with include? and fetch and nested hashes 726 [Nicholas Seckar]
  • Added Object#blank? — see redhanded.hobix.com/inspect/objectBlank.html 783 [_why the lucky stiff]
  • Added inflection rules for "sh" words, like "wish" and "fish" 755 [phillip@pjbsoftware.com]
  • Fixed an exception when using Ajax based requests from Safari because Safari appends a \000 to the post body. Symbols can‘t have \000 in them so indifferent access would throw an exception in the constructor. Indifferent hashes now use strings internally instead. 746 [Tobias Luetke]
  • Added String#to_time and String#to_date for wrapping ParseDate

*1.0.0* (24th February, 2005)

  • Added TimeZone as the first of a number of value objects that among others Active Record can use rich value objects using composed_of 688 [Jamis Buck]
  • Added Date::Conversions for getting dates in different convenient string representations and other objects
  • Added Time::Conversions for getting times in different convenient string representations and other objects
  • Added Time::Calculations to ask for things like Time.now.tomorrow, Time.now.yesterday, Time.now.months_ago(4) 580 [DP|Flurin]. Examples:
      "Later today"         => now.in(3.hours),
  "Tomorrow morning"    => now.tomorrow.change(:hour => 9),
  "Tomorrow afternoon"  => now.tomorrow.change(:hour => 14),
  "In a couple of days" => now.tomorrow.tomorrow.change(:hour => 9),
  "Next monday"         => now.next_week.change(:hour => 9),
  "In a month"          => now.next_month.change(:hour => 9),
  "In 6 months"         => now.months_since(6).change(:hour => 9),
  "In a year"           => now.in(1.year).change(:hour => 9)
  • Upgraded to breakpoint 92 which fixes:
      * overload IRB.parse_opts(), fixes #443
    => breakpoints in tests work even when running them via rake
  * untaint handlers, might fix an issue discussed on the Rails ML
  * added verbose mode to breakpoint_client
  * less noise caused by breakpoint_client by default
  * ignored TerminateLineInput exception in signal handler
    => quiet exit on Ctrl-C
  • Fixed Inflector for words like "news" and "series" that are the same in plural and singular 603 [echion], 615 [marcenuc]
  • Added Hash#stringify_keys and Hash#stringify_keys!
  • Added IndifferentAccess as a way to wrap a hash by a symbol-based store that also can be accessed by string keys
  • Added Inflector.constantize to turn "Admin::User" into a reference for the constant Admin::User
  • Added that Inflector.camelize and Inflector.underscore can deal with modules like turning "Admin::User" into "admin/user" and back
  • Added Inflector.humanize to turn attribute names like employee_salary into "Employee salary". Used by automated error reporting in AR.
  • Added availability of class inheritable attributes to the masses 477 [Jeremy Kemper]
      class Foo
    class_inheritable_reader :read_me
    class_inheritable_writer :write_me
    class_inheritable_accessor :read_and_write_me
    class_inheritable_array :read_and_concat_me
    class_inheritable_hash :read_and_update_me
  end

  # Bar gets a clone of (not a reference to) Foo's attributes.
  class Bar < Foo
  end

  Bar.read_and_write_me == Foo.read_and_write_me
  Bar.read_and_write_me = 'bar'
  Bar.read_and_write_me != Foo.read_and_write_me
  • Added Inflections as an extension on String, so Inflector.pluralize(Inflector.classify(name)) becomes name.classify.pluralize 476 [Jeremy Kemper]
  • Added Byte operations to Numeric, so 5.5.megabytes + 200.kilobytes 461 [Marcel Molina]
  • Fixed that Dependencies.reload can‘t load the same file twice 420 [Kent Sibilev]
  • Added Fixnum#ago/until, Fixnum#since/from_now 450 [Jeremy Kemper]
  • Added that Inflector now accepts Symbols and Classes by calling .to_s on the word supplied
  • Added time unit extensions to Fixnum that‘ll return the period in seconds, like 2.days + 4.hours.


Class: Rails::Configuration

Class
Rails::Configuration
In: | railties/lib/initializer.rb
Parent: | Object

The Configuration class holds all the parameters for the Initializer and ships with defaults that suites most Rails applications. But it‘s possible to overwrite everything. Usually, you‘ll create an Configuration file implicitly through the block running on the Initializer, but it‘s also possible to create the Configuration instance in advance and pass it in like this:

  config = Rails::Configuration.new
  Rails::Initializer.run(:process, config)
Methods
  • after_initialize
  • after_initialize_blocks
  • breakpoint_server
  • breakpoint_server=
  • builtin_directories
  • database_configuration
  • environment
  • environment_path
  • framework_paths
  • new
  • plugins=
  • set_root_path!
  • to_prepare
Attributes
[RW] | action_controller | A stub for setting options on ActionController::Base
[RW] | action_mailer | A stub for setting options on ActionMailer::Base
[RW] | action_view | A stub for setting options on ActionView::Base
[RW] | active_record | A stub for setting options on ActiveRecord::Base
[RW] | active_resource | A stub for setting options on ActiveRecord::Base
[RW] | cache_classes | Whether or not classes should be cached (set to false if you want application classes to be reloaded on each request)
[RW] | controller_paths | The list of paths that should be searched for controllers. (Defaults to app/controllers and components.)
[RW] | database_configuration_file | The path to the database configuration file to use. (Defaults to config/database.yml.)
[RW] | frameworks | The list of rails framework components that should be loaded. (Defaults to :active_record, :action_controller, :action_view, :action_mailer, and :active_resource).
[RW] | load_once_paths | An array of paths from which Rails will automatically load from only once. All elements of this array must also be in load_paths.
[RW] | load_paths | An array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list.
[RW] | log_level | The log level to use for the default Rails logger. In production mode, this defaults to :info. In development mode, it defaults to :debug.
[RW] | log_path | The path to the log file to use. Defaults to log/#{environment}.log (e.g. log/development.log or log/production.log).
[RW] | logger | The specific logger to use. By default, a logger will be created and initialized using log_path and log_level, but a programmer may specifically set the logger to use via this accessor and it will be used directly.
[RW] | plugin_loader | The class that handles loading each plugin. Defaults to Rails::Plugin::Loader, but a sub class would have access to fine grained modification of the loading behavior. See the implementation of Rails::Plugin::Loader for more details.
[RW] | plugin_locators | The classes that handle finding the desired plugins that you‘d like to load for your application. By default it is the Rails::Plugin::FileSystemLocator which finds plugins to load in vendor/plugins. You can hook into gem location by subclassing Rails::Plugin::Locator and adding it onto the list of plugin_locators.
[RW] | plugin_paths | The path to the root of the plugins directory. By default, it is in vendor/plugins.
[R] | plugins | The list of plugins to load. If this is set to nil, all plugins will be loaded. If this is set to [], no plugins will be loaded. Otherwise, plugins will be loaded in the order specified.
[R] | root_path | The application‘s base directory.
[RW] | view_path | The root of the application‘s views. (Defaults to app/views.)
[RW] | whiny_nils | Set to true if you want to be warned (noisily) when you try to invoke any method of nil. Set to false for the standard Ruby behavior.
Public Class methods
new()

Create a new Configuration instance, initialized with the default values.

[ show source ]

     # File railties/lib/initializer.rb, line 460
460:     def initialize
461:       set_root_path!
462:
463:       self.frameworks                   = default_frameworks
464:       self.load_paths                   = default_load_paths
465:       self.load_once_paths              = default_load_once_paths
466:       self.log_path                     = default_log_path
467:       self.log_level                    = default_log_level
468:       self.view_path                    = default_view_path
469:       self.controller_paths             = default_controller_paths
470:       self.cache_classes                = default_cache_classes
471:       self.whiny_nils                   = default_whiny_nils
472:       self.plugins                      = default_plugins
473:       self.plugin_paths                 = default_plugin_paths
474:       self.plugin_locators              = default_plugin_locators
475:       self.plugin_loader                = default_plugin_loader
476:       self.database_configuration_file  = default_database_configuration_file
477:
478:       for framework in default_frameworks
479:         self.send("#{framework}=", Rails::OrderedOptions.new)
480:       end
481:     end
Public Instance methods
after_initialize(&after_initialize_block)

Adds a block which will be executed after rails has been fully initialized. Useful for per-environment configuration which depends on the framework being fully initialized.

[ show source ]

     # File railties/lib/initializer.rb, line 525
525:     def after_initialize(&after_initialize_block)
526:       after_initialize_blocks << after_initialize_block if after_initialize_block
527:     end
after_initialize_blocks()

Returns the blocks added with Configuration#after_initialize

[ show source ]

     # File railties/lib/initializer.rb, line 530
530:     def after_initialize_blocks
531:       @after_initialize_blocks ||= []
532:     end
breakpoint_server(_ = nil)

Deprecated options:

This method is also aliased as breakpoint_server=

[ show source ]

     # File railties/lib/initializer.rb, line 449
449:     def breakpoint_server(_ = nil)
450:       $stderr.puts %(
451:       *******************************************************************
452:       * config.breakpoint_server has been deprecated and has no effect. *
453:       *******************************************************************
454:       )
455:     end
breakpoint_server=(_ = nil)

Alias for breakpoint_server

builtin_directories()

[ show source ]

     # File railties/lib/initializer.rb, line 543
543:     def builtin_directories
544:       # Include builtins only in the development environment.
545:       (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
546:     end
database_configuration()

Loads and returns the contents of the database_configuration_file. The contents of the file are processed via ERB before being sent through YAML::load.

[ show source ]

     # File railties/lib/initializer.rb, line 506
506:     def database_configuration
507:       YAML::load(ERB.new(IO.read(database_configuration_file)).result)
508:     end
environment()

Return the currently selected environment. By default, it returns the value of the RAILS_ENV constant.

[ show source ]

     # File railties/lib/initializer.rb, line 518
518:     def environment
519:       ::RAILS_ENV
520:     end
environment_path()

The path to the current environment‘s file (development.rb, etc.). By default the file is at config/environments/#{environment}.rb.

[ show source ]

     # File railties/lib/initializer.rb, line 512
512:     def environment_path
513:       "#{root_path}/config/environments/#{environment}.rb"
514:     end
framework_paths()

[ show source ]

     # File railties/lib/initializer.rb, line 548
548:     def framework_paths
549:       paths = %w(railties railties/lib activesupport/lib)
550:       paths << 'actionpack/lib' if frameworks.include? :action_controller or frameworks.include? :action_view
551:
552:       [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
553:         paths << "#{framework.to_s.gsub('_', '')}/lib" if frameworks.include? framework
554:       end
555:
556:       paths.map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
557:     end
plugins=(plugins)

[ show source ]

     # File railties/lib/initializer.rb, line 429
429:     def plugins=(plugins)
430:       @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
431:     end
set_root_path!()

Set the root_path to RAILS_ROOT and canonicalize it.

[ show source ]

     # File railties/lib/initializer.rb, line 484
484:     def set_root_path!
485:       raise 'RAILS_ROOT is not set' unless defined?(::RAILS_ROOT)
486:       raise 'RAILS_ROOT is not a directory' unless File.directory?(::RAILS_ROOT)
487:
488:       @root_path =
489:         # Pathname is incompatible with Windows, but Windows doesn't have
490:         # real symlinks so File.expand_path is safe.
491:         if RUBY_PLATFORM =~ /(:?mswin|mingw)/
492:           File.expand_path(::RAILS_ROOT)
493:
494:         # Otherwise use Pathname#realpath which respects symlinks.
495:         else
496:           Pathname.new(::RAILS_ROOT).realpath.to_s
497:         end
498:
499:       Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT)
500:       ::RAILS_ROOT.replace @root_path
501:     end
to_prepare(&callback)

Add a preparation callback that will run before every request in development mode, or before the first request in production.

See Dispatcher#to_prepare.

[ show source ]

     # File railties/lib/initializer.rb, line 538
538:     def to_prepare(&callback)
539:       require 'dispatcher' unless defined?(::Dispatcher)
540:       Dispatcher.to_prepare(&callback)
541:     end


Class: Rails::Initializer

Class
Rails::Initializer
In: | railties/lib/initializer.rb
Parent: | Object

The Initializer is responsible for processing the Rails configuration, such as setting the $LOAD_PATH, requiring the right frameworks, initializing logging, and more. It can be run either as a single command that‘ll just use the default configuration, like this:

  Rails::Initializer.run

But normally it‘s more interesting to pass in a custom configuration through the block running:

  Rails::Initializer.run do |config|
    config.frameworks -= [ :action_mailer ]
  end

This will use the default configuration options from Rails::Configuration, but allow for overwriting on select areas.

Methods
  • add_plugin_load_paths
  • add_support_load_paths
  • after_initialize
  • check_ruby_version
  • initialize_database
  • initialize_dependency_mechanism
  • initialize_encoding
  • initialize_framework_logging
  • initialize_framework_settings
  • initialize_framework_views
  • initialize_logger
  • initialize_routing
  • initialize_temporary_directories
  • initialize_whiny_nils
  • load_application_initializers
  • load_environment
  • load_observers
  • load_plugins
  • new
  • plugin_loader
  • process
  • require_frameworks
  • run
  • set_autoload_paths
  • set_load_path
Attributes
[R] | configuration | The Configuration instance used by this Initializer instance.
[R] | loaded_plugins | The set of loaded plugins.
Public Class methods
new(configuration)

Create a new Initializer instance that references the given Configuration instance.

[ show source ]

    # File railties/lib/initializer.rb, line 55
55:     def initialize(configuration)
56:       @configuration = configuration
57:       @loaded_plugins = []
58:     end
run(command = :process, configuration = Configuration.new) {|configuration if block_given?| ...}

Runs the initializer. By default, this will invoke the process method, which simply executes all of the initialization routines. Alternately, you can specify explicitly which initialization routine you want:

  Rails::Initializer.run(:set_load_path)

This is useful if you only want the load path initialized, without incuring the overhead of completely loading the entire environment.

[ show source ]

    # File railties/lib/initializer.rb, line 46
46:     def self.run(command = :process, configuration = Configuration.new)
47:       yield configuration if block_given?
48:       initializer = new configuration
49:       initializer.send(command)
50:       initializer
51:     end
Public Instance methods
add_plugin_load_paths()

Adds all load paths from plugins to the global set of load paths, so that code from plugins can be required (explicitly or automatically via Dependencies).

[ show source ]

     # File railties/lib/initializer.rb, line 169
169:     def add_plugin_load_paths
170:       plugin_loader.add_plugin_load_paths
171:     end
add_support_load_paths()

Add the load paths used by support functions such as the info controller

[ show source ]

     # File railties/lib/initializer.rb, line 164
164:     def add_support_load_paths
165:     end
after_initialize()

Fires the user-supplied after_initialize block (Configuration#after_initialize)

[ show source ]

     # File railties/lib/initializer.rb, line 335
335:     def after_initialize
336:       configuration.after_initialize_blocks.each do |block|
337:         block.call
338:       end
339:     end
check_ruby_version()

Check for valid Ruby version This is done in an external file, so we can use it from the `rails` program as well without duplication.

[ show source ]

     # File railties/lib/initializer.rb, line 122
122:     def check_ruby_version
123:       require 'ruby_version_check'
124:     end
initialize_database()

This initialization routine does nothing unless :active_record is one of the frameworks to load (Configuration#frameworks). If it is, this sets the database configuration from Configuration#database_configuration and then establishes the connection.

[ show source ]

     # File railties/lib/initializer.rb, line 232
232:     def initialize_database
233:       if configuration.frameworks.include?(:active_record)
234:         ActiveRecord::Base.configurations = configuration.database_configuration
235:         ActiveRecord::Base.establish_connection
236:       end
237:     end
initialize_dependency_mechanism()

Sets the dependency loading mechanism based on the value of Configuration#cache_classes.

[ show source ]

     # File railties/lib/initializer.rb, line 299
299:     def initialize_dependency_mechanism
300:       Dependencies.mechanism = configuration.cache_classes ? :require : :load
301:     end
initialize_encoding()

This initialization sets $KCODE to ‘u’ to enable the multibyte safe operations. Plugin authors supporting other encodings should override this behaviour and set the relevant default_charset on ActionController::Base

[ show source ]

     # File railties/lib/initializer.rb, line 224
224:     def initialize_encoding
225:       $KCODE='u'
226:     end
initialize_framework_logging()

Sets the logger for ActiveRecord, ActionController, and ActionMailer (but only for those frameworks that are to be loaded). If the framework‘s logger is already set, it is not changed, otherwise it is set to use RAILS_DEFAULT_LOGGER.

[ show source ]

     # File railties/lib/initializer.rb, line 273
273:     def initialize_framework_logging
274:       for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
275:         framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER
276:       end
277:     end
initialize_framework_settings()

Initializes framework-specific settings for each of the loaded frameworks (Configuration#frameworks). The available settings map to the accessors on each of the corresponding Base classes.

[ show source ]

     # File railties/lib/initializer.rb, line 324
324:     def initialize_framework_settings
325:       configuration.frameworks.each do |framework|
326:         base_class = framework.to_s.camelize.constantize.const_get("Base")
327:
328:         configuration.send(framework).each do |setting, value|
329:           base_class.send("#{setting}=", value)
330:         end
331:       end
332:     end
initialize_framework_views()

Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+ (but only for those frameworks that are to be loaded). If the framework‘s paths have already been set, it is not changed, otherwise it is set to use Configuration#view_path.

[ show source ]

     # File railties/lib/initializer.rb, line 283
283:     def initialize_framework_views
284:       ActionMailer::Base.template_root ||= configuration.view_path  if configuration.frameworks.include?(:action_mailer)
285:       ActionController::Base.view_paths = [configuration.view_path] if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty?
286:     end
initialize_logger()

If the RAILS_DEFAULT_LOGGER constant is already set, this initialization routine does nothing. If the constant is not set, and Configuration#logger is not nil, this also does nothing. Otherwise, a new logger instance is created at Configuration#log_path, with a default log level of Configuration#log_level.

If the log could not be created, the log will be set to output to STDERR, with a log level of WARN.

[ show source ]

     # File railties/lib/initializer.rb, line 247
247:     def initialize_logger
248:       # if the environment has explicitly defined a logger, use it
249:       return if defined?(RAILS_DEFAULT_LOGGER)
250:
251:       unless logger = configuration.logger
252:         begin
253:           logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
254:           logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
255:           logger.auto_flushing = false if configuration.environment == "production"
256:         rescue StandardError =>e
257:           logger = ActiveSupport::BufferedLogger.new(STDERR)
258:           logger.level = ActiveSupport::BufferedLogger::WARN
259:           logger.warn(
260:             "Rails Error: Unable to access log file. Please ensure that #{configuration.log_path} exists and is chmod 0666. " +
261:             "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
262:           )
263:         end
264:       end
265:
266:       silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
267:     end
initialize_routing()

If ActionController is not one of the loaded frameworks (Configuration#frameworks) this does nothing. Otherwise, it loads the routing definitions and sets up loading module used to lazily load controllers (Configuration#controller_paths).

[ show source ]

     # File railties/lib/initializer.rb, line 291
291:     def initialize_routing
292:       return unless configuration.frameworks.include?(:action_controller)
293:       ActionController::Routing.controller_paths = configuration.controller_paths
294:       ActionController::Routing::Routes.reload
295:     end
initialize_temporary_directories()

[ show source ]

     # File railties/lib/initializer.rb, line 309
309:     def initialize_temporary_directories
310:       if configuration.frameworks.include?(:action_controller)
311:         session_path = "#{configuration.root_path}/tmp/sessions/"
312:         ActionController::Base.session_options[:tmpdir] = File.exist?(session_path) ? session_path : Dir::tmpdir
313:
314:         cache_path = "#{configuration.root_path}/tmp/cache/"
315:         if File.exist?(cache_path)
316:           ActionController::Base.fragment_cache_store = :file_store, cache_path
317:         end
318:       end
319:     end
initialize_whiny_nils()

Loads support for "whiny nil" (noisy warnings when methods are invoked on nil values) if Configuration#whiny_nils is true.

[ show source ]

     # File railties/lib/initializer.rb, line 305
305:     def initialize_whiny_nils
306:       require('active_support/whiny_nil') if configuration.whiny_nils
307:     end
load_application_initializers()

[ show source ]

     # File railties/lib/initializer.rb, line 341
341:     def load_application_initializers
342:       Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
343:         load(initializer)
344:       end
345:     end
load_environment()

Loads the environment specified by Configuration#environment_path, which is typically one of development, test, or production.

[ show source ]

     # File railties/lib/initializer.rb, line 199
199:     def load_environment
200:       silence_warnings do
201:         return if @environment_loaded
202:         @environment_loaded = true
203:
204:         config = configuration
205:         constants = self.class.constants
206:
207:         eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
208:
209:         (self.class.constants - constants).each do |const|
210:           Object.const_set(const, self.class.const_get(const))
211:         end
212:       end
213:     end
load_observers()

[ show source ]

     # File railties/lib/initializer.rb, line 215
215:     def load_observers
216:       if configuration.frameworks.include?(:active_record)
217:         ActiveRecord::Base.instantiate_observers
218:       end
219:     end
load_plugins()

Loads all plugins in config.plugin_paths. plugin_paths defaults to vendor/plugins but may also be set to a list of paths, such as

  config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]

In the default implementation, as each plugin discovered in plugin_paths is initialized:

  • its lib directory, if present, is added to the load path (immediately after the applications lib directory)
  • init.rb is evaluated, if present

After all plugins are loaded, duplicates are removed from the load path. If an array of plugin names is specified in config.plugins, only those plugins will be loaded and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical order.

if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other plugins will be loaded in alphabetical order

[ show source ]

     # File railties/lib/initializer.rb, line 189
189:     def load_plugins
190:       plugin_loader.load_plugins
191:     end
plugin_loader()

[ show source ]

     # File railties/lib/initializer.rb, line 193
193:     def plugin_loader
194:       @plugin_loader ||= configuration.plugin_loader.new(self)
195:     end
process()

Sequentially step through all of the available initialization routines, in order:

  • check_ruby_version
  • set_load_path
  • require_frameworks
  • set_autoload_paths
  • add_plugin_load_paths
  • load_environment
  • initialize_encoding
  • initialize_database
  • initialize_logger
  • initialize_framework_logging
  • initialize_framework_views
  • initialize_dependency_mechanism
  • initialize_whiny_nils
  • initialize_temporary_directories
  • initialize_framework_settings
  • add_support_load_paths
  • load_plugins
  • load_observers
  • initialize_routing
  • after_initialize
  • load_application_initializers

[ show source ]

     # File railties/lib/initializer.rb, line 84
 84:     def process
 85:       check_ruby_version
 86:       set_load_path
 87:
 88:       require_frameworks
 89:       set_autoload_paths
 90:       add_plugin_load_paths
 91:       load_environment
 92:
 93:       initialize_encoding
 94:       initialize_database
 95:       initialize_logger
 96:       initialize_framework_logging
 97:       initialize_framework_views
 98:       initialize_dependency_mechanism
 99:       initialize_whiny_nils
100:       initialize_temporary_directories
101:       initialize_framework_settings
102:
103:       add_support_load_paths
104:
105:       load_plugins
106:
107:       # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
108:       load_observers
109:
110:       # Routing must be initialized after plugins to allow the former to extend the routes
111:       initialize_routing
112:
113:       # the framework is now fully initialized
114:       after_initialize
115:
116:       load_application_initializers
117:     end
require_frameworks()

Requires all frameworks specified by the Configuration#frameworks list. By default, all frameworks (ActiveRecord, ActiveSupport, ActionPack, ActionMailer, and ActiveResource) are loaded.

[ show source ]

     # File railties/lib/initializer.rb, line 156
156:     def require_frameworks
157:       configuration.frameworks.each { |framework| require(framework.to_s) }
158:     rescue LoadError => e
159:       # re-raise because Mongrel would swallow it
160:       raise e.to_s
161:     end
set_autoload_paths()

Set the paths from which Rails will automatically load source files, and the load_once paths.

[ show source ]

     # File railties/lib/initializer.rb, line 136
136:     def set_autoload_paths
137:       Dependencies.load_paths = configuration.load_paths.uniq
138:       Dependencies.load_once_paths = configuration.load_once_paths.uniq
139:
140:       extra = Dependencies.load_once_paths - Dependencies.load_paths
141:       unless extra.empty?
142:         abort "load_once_paths must be a subset of the load_paths.\nExtra items in load_once_paths: \#{extra * ','}\n"
143:       end
144:
145:       # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
146:       configuration.load_once_paths.freeze
147:     end
set_load_path()

Set the $LOAD_PATH based on the value of Configuration#load_paths. Duplicates are removed.

[ show source ]

     # File railties/lib/initializer.rb, line 128
128:     def set_load_path
129:       load_paths = configuration.load_paths + configuration.framework_paths
130:       load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
131:       $LOAD_PATH.uniq!
132:     end


Class: RailsFCGIHandler

Class
RailsFCGIHandler
In: | railties/lib/fcgi_handler.rb
Parent: | Object
Methods
  • close_connection
  • dispatcher_error
  • dispatcher_log
  • exit_handler
  • exit_now_handler
  • gc_countdown
  • install_signal_handler
  • install_signal_handlers
  • logger
  • mark_features!
  • new
  • process!
  • process!
  • process_each_request
  • process_request
  • reload!
  • reload_handler
  • restart!
  • restart_handler
  • restore!
  • run_gc!
  • with_signal_handler
Constants
SIGNALS | = | { 'HUP' => :reload, 'INT' => :exit_now, 'TERM' => :exit_now, 'USR1' => :exit, 'USR2' => :restart
GLOBAL_SIGNALS | = | SIGNALS.keys - %w(USR1)
Attributes
[RW] | gc_request_period
[RW] | log_file_path
[R] | when_ready
Public Class methods
new(log_file_path = nil, gc_request_period = nil) {|self if block_given?| ...}

Initialize the FastCGI instance with the path to a crash log detailing unhandled exceptions (default RAILS_ROOT/log/fastcgi.crash.log) and the number of requests to process between garbage collection runs (default nil for normal GC behavior.) Optionally, pass a block which takes this instance as an argument for further configuration.

[ show source ]

    # File railties/lib/fcgi_handler.rb, line 32
32:   def initialize(log_file_path = nil, gc_request_period = nil)
33:     self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log"
34:     self.gc_request_period = gc_request_period
35:
36:     # Yield for additional configuration.
37:     yield self if block_given?
38:
39:     # Safely install signal handlers.
40:     install_signal_handlers
41:
42:     # Start error timestamp at 11 seconds ago.
43:     @last_error_on = Time.now - 11
44:   end
process!(*args, &block)

Initialize and run the FastCGI instance, passing arguments through to new.

[ show source ]

    # File railties/lib/fcgi_handler.rb, line 23
23:   def self.process!(*args, &block)
24:     new(*args, &block).process!
25:   end
Public Instance methods
process!(provider = FCGI)

[ show source ]

    # File railties/lib/fcgi_handler.rb, line 46
46:   def process!(provider = FCGI)
47:     mark_features!
48:
49:     dispatcher_log :info, 'starting'
50:     process_each_request provider
51:     dispatcher_log :info, 'stopping gracefully'
52:
53:   rescue Exception => error
54:     case error
55:     when SystemExit
56:       dispatcher_log :info, 'stopping after explicit exit'
57:     when SignalException
58:       dispatcher_error error, 'stopping after unhandled signal'
59:     else
60:       # Retry if exceptions occur more than 10 seconds apart.
61:       if Time.now - @last_error_on > 10
62:         @last_error_on = Time.now
63:         dispatcher_error error, 'retrying after unhandled exception'
64:         retry
65:       else
66:         dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last'
67:       end
68:     end
69:   end
Protected Instance methods
close_connection(cgi)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 220
220:     def close_connection(cgi)
221:       cgi.instance_variable_get("@request").finish if cgi
222:     end
dispatcher_error(e, msg = "")

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 122
122:     def dispatcher_error(e, msg = "")
123:       error_message =
124:         "Dispatcher failed to catch: #{e} (#{e.class})\n" +
125:         "  #{e.backtrace.join("\n  ")}\n#{msg}"
126:       dispatcher_log(:error, error_message)
127:     end
dispatcher_log(level, msg)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 114
114:     def dispatcher_log(level, msg)
115:       time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
116:       logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
117:     rescue Exception => log_error  # Logger errors
118:       STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
119:       STDERR << "  #{log_error.class}: #{log_error.message}\n"
120:     end
exit_handler(signal)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 159
159:     def exit_handler(signal)
160:       dispatcher_log :info, "asked to stop ASAP"
161:       @when_ready = :exit
162:     end
exit_now_handler(signal)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 154
154:     def exit_now_handler(signal)
155:       dispatcher_log :info, "asked to stop immediately"
156:       exit
157:     end
gc_countdown()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 212
212:     def gc_countdown
213:       if gc_request_period
214:         @gc_request_countdown ||= gc_request_period
215:         @gc_request_countdown -= 1
216:         run_gc! if @gc_request_countdown <= 0
217:       end
218:     end
install_signal_handler(signal, handler = nil)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 133
133:     def install_signal_handler(signal, handler = nil)
134:       if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler")
135:         handler ||= method(name).to_proc
136:
137:         begin
138:           trap(signal, handler)
139:         rescue ArgumentError
140:           dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
141:         end
142:       else
143:         dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
144:       end
145:     end
install_signal_handlers()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 129
129:     def install_signal_handlers
130:       GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) }
131:     end
logger()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 110
110:     def logger
111:       @logger ||= Logger.new(@log_file_path)
112:     end
mark_features!()

Make a note of $" so we can safely reload this instance.

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 197
197:     def mark_features!
198:       @features = $".clone
199:     end
process_each_request(provider)

[ show source ]

    # File railties/lib/fcgi_handler.rb, line 73
73:     def process_each_request(provider)
74:       cgi = nil
75:
76:       provider.each_cgi do |cgi|
77:         process_request(cgi)
78:
79:         case when_ready
80:           when :reload
81:             reload!
82:           when :restart
83:             close_connection(cgi)
84:             restart!
85:           when :exit
86:             close_connection(cgi)
87:             break
88:         end
89:       end
90:     rescue SignalException => signal
91:       raise unless signal.message == 'SIGUSR1'
92:       close_connection(cgi)
93:     end
process_request(cgi)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 95
 95:     def process_request(cgi)
 96:       @when_ready = nil
 97:       gc_countdown
 98:
 99:       with_signal_handler 'USR1' do
100:         begin
101:           Dispatcher.dispatch(cgi)
102:         rescue SignalException, SystemExit
103:           raise
104:         rescue Exception => error
105:           dispatcher_error error, 'unhandled dispatch error'
106:         end
107:       end
108:     end
reload!()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 189
189:     def reload!
190:       run_gc! if gc_request_period
191:       restore!
192:       @when_ready = nil
193:       dispatcher_log :info, "reloaded"
194:     end
reload_handler(signal)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 164
164:     def reload_handler(signal)
165:       dispatcher_log :info, "asked to reload ASAP"
166:       @when_ready = :reload
167:     end
restart!()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 174
174:     def restart!
175:       config       = ::Config::CONFIG
176:       ruby         = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
177:       command_line = [ruby, $0, ARGV].flatten.join(' ')
178:
179:       dispatcher_log :info, "restarted"
180:
181:       # close resources as they won't be closed by
182:       # the OS when using exec
183:       logger.close rescue nil
184:       RAILS_DEFAULT_LOGGER.close rescue nil
185:
186:       exec(command_line)
187:     end
restart_handler(signal)

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 169
169:     def restart_handler(signal)
170:       dispatcher_log :info, "asked to restart ASAP"
171:       @when_ready = :restart
172:     end
restore!()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 201
201:     def restore!
202:       $".replace @features
203:       Dispatcher.reset_application!
204:       ActionController::Routing::Routes.reload
205:     end
run_gc!()

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 207
207:     def run_gc!
208:       @gc_request_countdown = gc_request_period
209:       GC.enable; GC.start; GC.disable
210:     end
with_signal_handler(signal) {|| ...}

[ show source ]

     # File railties/lib/fcgi_handler.rb, line 147
147:     def with_signal_handler(signal)
148:       install_signal_handler(signal)
149:       yield
150:     ensure
151:       install_signal_handler(signal, 'DEFAULT')
152:     end


File: code_statistics.rb

File
code_statistics.rb
Path: | railties/lib/code_statistics.rb
Modified: | Sun Mar 02 11:09:11 -0700 2008


File: commands.rb

File
commands.rb
Path: | railties/lib/commands.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008


File: console_app.rb

File
console_app.rb
Path: | railties/lib/console_app.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008

Required Files
  • action_controller/integration
Methods
  • app
  • new_session
  • reload!
Public Instance methods
app(create=false)

reference the global "app" instance, created on demand. To recreate the instance, pass a non-false value as the parameter.

[ show source ]

    # File railties/lib/console_app.rb, line 8
 8: def app(create=false)
 9:   @app_integration_instance = nil if create
10:   @app_integration_instance ||= new_session do |sess|
11:     sess.host! "www.example.com"
12:   end
13: end
new_session() {|session if block_given?| ...}

create a new session. If a block is given, the new session will be yielded to the block before being returned.

[ show source ]

    # File railties/lib/console_app.rb, line 17
17: def new_session
18:   session = ActionController::Integration::Session.new
19:   yield session if block_given?
20:   session
21: end
reload!()

reloads the environment

[ show source ]

    # File railties/lib/console_app.rb, line 24
24: def reload!
25:   puts "Reloading..."
26:   dispatcher = ActionController::Dispatcher.new($stdout)
27:   dispatcher.cleanup_application(true)
28:   dispatcher.prepare_application(true)
29:   true
30: end


File: console_sandbox.rb

File
console_sandbox.rb
Path: | railties/lib/console_sandbox.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008


File: console_with_helpers.rb

File
console_with_helpers.rb
Path: | railties/lib/console_with_helpers.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008

Required Files
  • application
Methods
  • helper
Public Instance methods
helper(*helper_names)

[ show source ]

    # File railties/lib/console_with_helpers.rb, line 13
13: def helper(*helper_names)
14:   returning @helper_proxy ||= Object.new do |helper|
15:     helper_names.each { |h| helper.extend "#{h}_helper".classify.constantize }
16:   end
17: end


File: dispatcher.rb

File
dispatcher.rb
Path: | railties/lib/dispatcher.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008

Required Files
  • action_controller/dispatcher
Constants
Dispatcher = ActionController::Dispatcher


File: fcgi_handler.rb

File
fcgi_handler.rb
Path: | railties/lib/fcgi_handler.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008

Required Files
  • fcgi
  • logger
  • dispatcher
  • rbconfig


File: initializer.rb

File
initializer.rb
Path: | railties/lib/initializer.rb
Modified: | Sun Mar 02 11:09:13 -0700 2008

Required Files
  • logger
  • set
  • pathname
  • railties_path
  • rails/version
  • rails/plugin/locator
  • rails/plugin/loader
  • ruby_version_check
  • active_support/whiny_nil
  • dispatcher
Constants
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)


File: rails_generator.rb

File
rails_generator.rb
Path: | railties/lib/rails_generator.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008

Required Files
  • active_support
  • rubygems
  • rails_generator/base
  • rails_generator/lookup
  • rails_generator/commands
  • rails_generator/simple_logger


File: railties_path.rb

File
railties_path.rb
Path: | railties/lib/railties_path.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008

Constants
RAILTIES_PATH = File.join(File.dirname(__FILE__), '..')


File: ruby_version_check.rb

File
ruby_version_check.rb
Path: | railties/lib/ruby_version_check.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008


File: rubyprof_ext.rb

File
rubyprof_ext.rb
Path: | railties/lib/rubyprof_ext.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008

Required Files
  • prof


File: source_annotation_extractor.rb

File
source_annotation_extractor.rb
Path: | railties/lib/source_annotation_extractor.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008


File: test_help.rb

File
test_help.rb
Path: | railties/lib/test_help.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008

Required Files
  • test/unit
  • active_support/test_case
  • active_record/fixtures
  • action_controller/test_case
  • action_controller/test_process
  • action_controller/integration
  • action_mailer/test_case
Methods
  • create_fixtures
Constants
RAILS_ENV = "test" }
Public Instance methods
create_fixtures(*table_names)

[ show source ]

    # File railties/lib/test_help.rb, line 18
18: def create_fixtures(*table_names)
19:   Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
20: end


File: webrick_server.rb

File
webrick_server.rb
Path: | railties/lib/webrick_server.rb
Modified: | Sun Mar 02 11:09:15 -0700 2008

Donated by Florian Gross

Required Files
  • webrick
  • cgi
  • stringio
  • dispatcher
Included Modules
  • WEBrick


Module: ActiveResource

Module
ActiveResource
In: activeresource/lib/active_resource/base.rb activeresource/lib/active_resource/connection.rb activeresource/lib/active_resource/custom_methods.rb activeresource/lib/active_resource/formats/json_format.rb activeresource/lib/active_resource/formats/xml_format.rb activeresource/lib/active_resource/formats.rb activeresource/lib/active_resource/http_mock.rb activeresource/lib/active_resource/validations.rb activeresource/lib/active_resource/version.rb

A module to support custom REST methods and sub-resources, allowing you to break out of the "default" REST methods with your own custom resource requests. For example, say you use Rails to expose a REST service and configure your routes with:

   map.resources :people, :new => { :register => :post },
                          :element => { :promote => :put, :deactivate => :delete }
                          :collection => { :active => :get }

 This route set creates routes for the following http requests:

   POST    /people/new/register.xml #=> PeopleController.register
   PUT     /people/1/promote.xml    #=> PeopleController.promote with :id => 1
   DELETE  /people/1/deactivate.xml #=> PeopleController.deactivate with :id => 1
   GET     /people/active.xml       #=> PeopleController.active

Using this module, Active Resource can use these custom REST methods just like the standard methods.

  class Person < ActiveResource::Base
    self.site = "http://37s.sunrise.i:3000"
  end

  Person.new(:name => 'Ryan).post(:register)  # POST /people/new/register.xml
  # => { :id => 1, :name => 'Ryan' }

  Person.find(1).put(:promote, :position => 'Manager') # PUT /people/1/promote.xml
  Person.find(1).delete(:deactivate) # DELETE /people/1/deactivate.xml

  Person.get(:active)  # GET /people/active.xml
  # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
Classes and Modules
Module ActiveResource::CustomMethods
Module ActiveResource::Formats
Module ActiveResource::Validations
Class ActiveResource::BadRequest
Class ActiveResource::Base
Class ActiveResource::ClientError
Class ActiveResource::Connection
Class ActiveResource::Errors
Class ActiveResource::ForbiddenAccess
Class ActiveResource::HttpMock
Class ActiveResource::InvalidRequestError
Class ActiveResource::Request
Class ActiveResource::ResourceConflict
Class ActiveResource::ResourceNotFound
Class ActiveResource::Response
Class ActiveResource::ServerError
Class ActiveResource::UnauthorizedAccess


Module: Rails

Module
Rails
In: railties/lib/initializer.rb
Classes and Modules
Class Rails::Configuration
Class Rails::Initializer


Class: ActiveRecord::ConnectionAdapters::MysqlAdapter

Class
ActiveRecord::ConnectionAdapters::MysqlAdapter
In: | activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
Parent: | AbstractAdapter

The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with the faster C-based MySQL/Ruby adapter (available both as a gem and from www.tmtm.org/en/mysql/ruby/).

Options:

  • :host — Defaults to localhost
  • :port — Defaults to 3306
  • :socket — Defaults to /tmp/mysql.sock
  • :username — Defaults to root
  • :password — Defaults to nothing
  • :database — The name of the database. No default, must be provided.
  • :encoding — (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection
  • :sslkey — Necessary to use MySQL with an SSL connection
  • :sslcert — Necessary to use MySQL with an SSL connection
  • :sslcapath — Necessary to use MySQL with an SSL connection
  • :sslcipher — Necessary to use MySQL with an SSL connection

By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your environment.rb file:

  ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
Methods
  • active?
  • charset
  • collation
  • create_database
  • current_database
  • disconnect!
  • drop_table
  • new
  • quote
  • quoted_false
  • quoted_true
  • reconnect!
  • rename_table
  • select_rows
  • show_variable
Constants
LOST_CONNECTION_ERROR_MESSAGES = [ "Server shutdown in progress", "Broken pipe", "Lost connection to MySQL server during query", "MySQL server has gone away"
Public Class methods
new(connection, logger, connection_options, config)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 163
163:       def initialize(connection, logger, connection_options, config)
164:         super(connection, logger)
165:         @connection_options, @config = connection_options, config
166:
167:         connect
168:       end
Public Instance methods
active?()

CONNECTION MANAGEMENT ====================================

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 244
244:       def active?
245:         if @connection.respond_to?(:stat)
246:           @connection.stat
247:         else
248:           @connection.query 'select 1'
249:         end
250:
251:         # mysql-ruby doesn't raise an exception when stat fails.
252:         if @connection.respond_to?(:errno)
253:           @connection.errno.zero?
254:         else
255:           true
256:         end
257:       rescue Mysql::Error
258:         false
259:       end
charset()

Returns the database character set.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 376
376:       def charset
377:         show_variable 'character_set_database'
378:       end
collation()

Returns the database collation strategy.

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 381
381:       def collation
382:         show_variable 'collation_database'
383:       end
create_database(name, options = {})

Create a new MySQL database with optional :charset and :collation. Charset defaults to utf8.

Example:

  create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
  create_database 'matt_development'
  create_database 'matt_development', :charset => :big5

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 359
359:       def create_database(name, options = {})
360:         if options[:collation]
361:           execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
362:         else
363:           execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
364:         end
365:       end
current_database()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 371
371:       def current_database
372:         select_value 'SELECT DATABASE() as db'
373:       end
disconnect!()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 266
266:       def disconnect!
267:         @connection.close rescue nil
268:       end
drop_table(table_name, options = {})

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 391
391:       def drop_table(table_name, options = {})
392:         super(table_name, options)
393:       end
quote(value, column = nil)

QUOTING ==================================================

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 198
198:       def quote(value, column = nil)
199:         if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
200:           s = column.class.string_to_binary(value).unpack("H*")[0]
201:           "x'#{s}'"
202:         elsif value.kind_of?(BigDecimal)
203:           "'#{value.to_s("F")}'"
204:         else
205:           super
206:         end
207:       end
quoted_false()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 225
225:       def quoted_false
226:         "0"
227:       end
quoted_true()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 221
221:       def quoted_true
222:         "1"
223:       end
reconnect!()

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 261
261:       def reconnect!
262:         disconnect!
263:         connect
264:       end
rename_table(table_name, new_name)

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 421
421:       def rename_table(table_name, new_name)
422:         execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
423:       end
select_rows(sql, name = nil)

DATABASE STATEMENTS ======================================

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 273
273:       def select_rows(sql, name = nil)
274:         @connection.query_with_result = true
275:         result = execute(sql, name)
276:         rows = []
277:         result.each { |row| rows << row }
278:         result.free
279:         rows
280:       end
show_variable(name)

SHOW VARIABLES LIKE ‘name‘

[ show source ]

     # File activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 452
452:       def show_variable(name)
453:         variables = select_all("SHOW VARIABLES LIKE '#{name}'")
454:         variables.first['Value'] unless variables.empty?
455:       end


File: mysql_adapter.rb

File
mysql_adapter.rb
Path: | activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/connection_adapters/abstract_adapter
  • set
  • active_record/vendor/mysql


File: postgresql_adapter.rb

File
postgresql_adapter.rb
Path: | activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/connection_adapters/abstract_adapter


File: sqlite3_adapter.rb

File
sqlite3_adapter.rb
Path: | activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/connection_adapters/sqlite_adapter


File: sqlite_adapter.rb

File
sqlite_adapter.rb
Path: | activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
Modified: | Sun Mar 02 11:08:51 -0700 2008

Required Files
  • active_record/connection_adapters/abstract_adapter


File: CHANGELOG

File
CHANGELOG
Path: | railties/CHANGELOG
Modified: | Sun Mar 02 11:09:10 -0700 2008

*2.0.2* (December 16th, 2007)

  • Changed the default database from mysql to sqlite3, so now running "rails myapp" will have a config/database.yml that‘s setup for SQLite3 (which in OS X Leopard is installed by default, so is the gem, so everything Just Works with no database configuration at all). To get a Rails application preconfigured for MySQL, just run "rails -d mysql myapp" [DHH]
  • Turned on ActionView::Base.cache_template_loading by default in config/environments/production.rb to prevent file system stat calls for every template loading to see if it changed (this means that you have to restart the application to see template changes in production mode) [DHH]
  • Introduce `rake secret` to output a crytographically secure secret key for use with cookie sessions 10363 [revans]
  • Fixed that local database creation should consider 127.0.0.1 local 9026 [parcelbrat]
  • Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs 10435 [boone]
  • Added db:migrate:redo and db:migrate:reset for rerunning existing migrations 10431, 10432 [matt]
  • RAILS_GEM_VERSION may be double-quoted also. 10443 [James Cox]
  • Update rails:freeze:gems to work with RubyGems 0.9.5. [Jeremy Kemper]

*2.0.1* (December 7th, 2007)

  • Fixed Active Record bug

*2.0.0* (December 6th, 2007)

  • The test task stops with a warning if you have pending migrations. 10377 [Josh Knowles]
  • Add warning to documentation about using transactional fixtures when the code under test uses transactions itself. Closes 7548 [thijsv]
  • Update Prototype to 1.6.0.1. [sam]
  • Update script.aculo.us to 1.8.0.1. [madrobby]
  • Added db:fixtures:identity as a way of locating what ID a foxy fixture was assigned 10332 [jbarnette]
  • Generated fixtures should not specify ids since theyre expected to be foxy fixtures 10330 [jbarnette]
  • Update to Prototype -r8232. [sam]
  • Introduce SecretKeyGenerator for more secure session secrets than CGI::Session‘s pseudo-random id generator. Consider extracting to Active Support later. 10286 [Hongli Lai]
  • RAILS_GEM_VERSION may be set to any valid gem version specifier. 10057 [Chad Woolley, Cheah Chu Yeow]
  • Load config/preinitializer.rb, if present, before loading the environment. 9943 [Chad Woolley]
  • FastCGI handler ignores unsupported signals like USR2 on Windows. [Grzegorz Derebecki]
  • Only load ActionMailer::TestCase if ActionMailer is loaded. Closes 10137 [defunkt]
  • Fixed that db:reset would use migrations instead of loading db/schema.rb [DHH]
  • Ensure the plugin loader only loads plugins once. Closes 10102 [haruki_zaemon]
  • Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. Closes 9795 [lazyatom]
  • Added —skip-timestamps to generators that produce models 10036 [Tim Pope]
  • Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. [sam, madrobby]
  • Added db:rollback to rollback the schema one version (or multiple as specified by STEP) [Jeffrey Allan Hardy]
  • Fix typo in test_helper. Closes 9925 [viktor tron]
  • Request profiler. [Jeremy Kemper]
  • config/boot.rb correctly detects RAILS_GEM_VERSION. 9834 [alexch, thewoolleyman]
  • Fixed incorrect migration number if script/generate executed outside of Rails root 7080 [jeremymcanally]
  • Update Prototype to 1.6.0_rc1 and script.aculo.us to 1.8.0 preview 0. [sam, madrobby]
  • Generated fixtures use the actual primary key instead of id. 4343 [Frederick Ros, Tarmo Tänav]
  • Extend the console helper method to allow you to include custom helpers. e.g: >> helper :posts >> helper.some_method_from_posts_helper(Post.find(1))
  • db:create works with remote databases whereas db:create:all only creates

databases on localhost. 9753 [Trevor Wennblom]

  • Removed calls to fixtures in generated tests as fixtures :all is now present by default in test_helper.rb [DHH]
  • Add —prefix option to script/server when using mongrel. [dacat]

*2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.1.4 - 1.2.3]

  • Fixed that installing plugins from SVN repositories that use trunk/ will work 8188 [evan]
  • Moved the SourceAnnotationExtractor to a separate file in case libraries try to load the rails rake tasks twice. [Rick]
  • Moved Dispatcher to ActionController::Dispatcher. [Jeremy Kemper]
  • Changed the default logger from Ruby‘s own Logger with the clean_logger extensions to ActiveSupport::BufferedLogger for performance reasons [DHH]. (You can change it back with config.logger = Logger.new("/path/to/log", level).)
  • Added a default 422.html page to be rendered when ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, or ActionController::InvalidAuthenticityToken is raised [DHH]
  • Added —skip-fixture option to script/generate model 6862 [sandofsky]
  • Print Rails version when starting console 7440 [eyematz]
  • Fixed the placement of fixture files for nested models when generating through script/generate model 7547 [jkit]
  • Added TEMPLATE option to rake doc:app to set a custom output template 7737 [Jakob S]
  • Added VERBOSE option to rake db:migrate to turn off output 8204 [jbarnette]
  • Fixed that rake doc:app should use UTF-8 8906 [farzy]
  • Fixes rake annotations to search erb and builder files as well 9150 [m.langenberg]
  • Removed web_service generator [Koz]
  • Added the :all option to config.plugins that‘ll include the rest of the plugins not already explicitly named 9613 [Frederick Cheung]. Example:
      # Loads :classic_pagination before all the other plugins
  config.plugins = [ :classic_pagination, :all ]
  • Added symbols as a legal way of specifying plugins in config.plugins 9629 [tom]
  • Removed deprecated task names, like clear_logs, in favor of the new namespaced style [DHH]
  • Support multiple config.after_initialize blocks so plugins and apps can more easily cooperate. 9582 [zdennis]
  • Added db:drop:all to drop all databases declared in config/database.yml [DHH]
  • Use attribute pairs instead of the migration name to create add and remove column migrations. Closes 9166 [Pratik Naik]
          For example:

      ruby script/generation migration AddSomeStuffToCustomers first_name:string last_name:string

      or

      ruby script/generation migration RemoveSomeStuffFromCustomers first_name:string last_name:string
  • Add ActiveResource to Rails::Info. Closes 8741 [kampers]
  • use Gem.find_name instead of search when freezing gems. Prevent false positives for other gems with rails in the name. Closes 8729 [wselman]
  • Automatically generate add/remove column commands in specially named migrations like AddLocationToEvent. Closes 9006 [zenspider]
  • Default to plural table name in Rails Generator if ActiveRecord is not present. Closes 8963 [evan]
  • Added rake routes for listing all the defined routes in the system. 8795 [Josh Peek]
  • db:create creates the database for the current environment if it‘s on localhost. db:create:all creates local databases for all environments. 8783 [matt]
  • Generators: look for generators in all gems, not just those suffixed with _generator, in the gem‘s generators or rails_generators directory. Allow use of the rails_generators directory instead of the standard generators directory in plugins also. 8730 [Dr Nic, topfunky]
  • MySQL, PostgreSQL: database.yml defaults to utf-8. 8701 [matt]
  • Added db:version to get the current schema number [via Err The Blog]
  • Added —skip-migration option to scaffold and resource generators 8656 [Michael Glaesemann]
  • Fix that FCGIs would leave log files open when asked to shut down by USR2. 3028 [Sebastian Kanthak, Josh Peek]
  • Fixed that dispatcher preparation callbacks only run once in production mode. Mock Routes.reload so that dispatcher preparation callback tests run. [Rick]
  • Fix syntax error in dispatcher than wrecked failsafe responses. 8625 [mtitorenko]
  • Scaffolded validation errors set the appropriate HTTP status for XML responses. 6946, 8622 [Manfred Stienstra, mmmultiworks]
  • Sexy migrations for the session_migration generator. 8561 [Vladislav]
  • Console reload! runs to_prepare callbacks also. 8393 [f.svehla]
  • Generated migrations include timestamps by default. 8501 [Shane Vitarana]
  • Drop Action Web Service from rails:freeze:edge. [Jeremy Kemper]
  • Add db:create, drop, reset, charset, and collation tasks. 8448 [matt]
  • Scaffold generator depends on model generator instead of duplicating it. 7222 [bscofield]
  • Scaffold generator tests. 8443 [pelle]
  • Generated scaffold functional tests use assert_difference. 8421 [Norbert Crombach]
  • Update to Prototype 1.5.1. [Sam Stephenson]
  • Update to script.aculo.us 1.7.1_beta3. [Thomas Fuchs]
  • Generators use *.html.erb view template naming. 8278 [Tim Pope]
  • Updated resource_scaffold and model generators to use short-hand style migrations [DHH]
  • Updated initializer to only load #{RAILS_ENV}.rb once. Added deprecation warning for config.breakpoint_server. [Nicholas Seckar]
  • Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]

    To use the new debugger, start your server with script/server —debugger and insert a call to ‘debugger’ (instead of ‘breakpoint’) where you want to jump into the debugger.

    BACKWARDS INCOMPATIBILITY NOTE: You must remove the default line 12 from config/environments/development.rb:

      config.breakpoint_server = true

    This configuration option is no longer available. Rails will fail to start in development mode as long as that‘s still present.

  • Resource scaffolding returns the created entity.to_xml. [Jeremy Kemper]
  • Resource scaffolding responds to new.xml. 8185 [Eric Mill]
  • Include Active Resource in rails:freeze:edge rake task. [Thomas Fuchs]
  • Include Active Resource instead of Action Web Service [DHH] You can add AWS back with this in config/environment.rb:
      config.load_paths += %W( #{RAILS_ROOT}/actionwebservice/lib )

    …or just gem ‘actionwebservice‘

  • Give generate scaffold a more descriptive database message. Closes 7316 [jeremymcanally]
  • Canonicalize RAILS_ROOT by using File.expand_path on Windows, which doesn‘t have to worry about symlinks, and Pathname#realpath elsewhere, which respects symlinks in relative paths but is incompatible with Windows. 6755 [Jeremy Kemper, trevor]
  • Deprecation: remove components from controller paths. [Jeremy Kemper]
  • Add environment variable RAILS_DEFAULT_DATABASE, which allows the builtin default of ‘mysql’ to be overridden. [Nicholas Seckar]
  • Windows: include MinGW in RUBY_PLATFORM check. 2982 [okkez000@gmail.com, Kaspar Schiess]
  • Split out the basic plugin locator functionality into an abstract super class. Add a FileSystemLocator to do the job of checking the plugin_paths for plugins. Add plugin_locators configuration option which will iterate over the set of plugin locators and load each of the plugin loaders they return. Rename locater everywhere to locator. [Marcel Molina Jr.]
  • Split plugin location and loading out of the initializer and into a new Plugin namespace, which includes Plugin::Locater and Plugin::Loader. The loader class that is used can be customized using the config.plugin_loader option. Those monkey patching the plugin loading subsystem take note, the internals changing here will likely break your modifications. The good news is that it should be substantially easier to hook into the plugin locating and loading process now. [Marcel Molina Jr.]
  • Added assumption that all plugin creators desire to be sharing individuals and release their work under the MIT license [DHH]
  • Added source-annotations extractor tasks to rake [Jamis Buck]. This allows you to add FIXME, OPTIMIZE, and TODO comments to your source code that can then be extracted in concert with rake notes (shows all), rake notes:fixme, rake notes:optimize and rake notes:todo.
  • Added fixtures :all to test_helper.rb to assume that most people just want all their fixtures loaded all the time [DHH]
  • Added config/initializers where all ruby files within it are automatically loaded after the Rails configuration is done, so you don‘t have to litter the environment.rb file with a ton of mixed stuff [DHH]
  • For new apps, generate a random secret for the cookie-based session store. [Jeremy Kemper]
  • Stop swallowing errors during rake test [Koz]
  • Update Rails Initializer to use ActionController::Base#view_paths [Rick]
  • Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
  • Plugins may be symlinked in vendor/plugins. 4245 [brandon, progrium@gmail.com]
  • Resource generator depends on the model generator rather than duplicating it. 7269 [bscofield]
  • Add/Update usage documentation for script/destroy, resource generator and scaffold_resource generator. Closes 7092, 7271, 7267. [bscofield]
  • Update to script.aculo.us 1.7.0. [Thomas Fuchs]
  • Update to Prototype 1.5.0. [Sam Stephenson]
  • Generator: use destination path for diff tempfiles. 7015 [alfeld]
  • Fixed that webrick would strip leading newlines and hang connection 4156 [psross]
  • Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick] If you really want your plugins to reload, add this to the very top of init.rb:
      Dependencies.load_once_paths.delete(lib_path)
  • Allow config.to_prepare to work, make the dispatcher safe to ‘re require’. [Koz, Nicholas Seckar]
  • Fix scaffold_resource generator so it respects the —pretend argument when creating the routes file. Closes 6852 [fearoffish]
  • Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes 4899 [Rick Olson]
  • Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam]
  • Don‘t generate a components directory in new Rails apps. [Jeremy Kemper]
  • Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
  • Added one-letter aliases for the three default environments to script/console, so script/console p will load the production environment (t for test, d for development) [DHH]
  • Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
  • Update initializer to load Rails::VERSION as soon as possible. Closes 6698. [Nicholas Seckar]
  • Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won‘t reread the schema if that doesn‘t happen (I‘m looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
  • Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
  • Update to Prototype and script.aculo.us [5579]. [Thomas Fuchs]
  • Made script/server work with -e and -d when using Mongrel [DHH]
  • Update to Prototype 1.5.0_rc2 [5550] which makes it work in Opera again [Thomas Fuchs]
  • Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Luetke]
  • Rails::VERSION::STRING should always be available without having to require ‘rails/version’. 6244 [fearoffish]
  • Update to Prototype 1.5.0_rc2. [Sam Stephenson]
  • Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck]
  • Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper]
  • Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes 6587. [Nicholas Seckar]
  • Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. 6584 [jchris]
  • Remove temporary crutch to help ApplicationController be unloaded. Closes 6496. [Nicholas Seckar]
  • scaffold_resource generator uses _path named routes and head instead of render :nothing => true. 6545 [Josh Susser]
  • Generator can show diff on file collision to help you decide whether to skip or overwrite. 6364 [jeffw, Jeremy Kemper]
  • Generated directories are recursively svn added, like mkdir -p. 6416 [NeilW]
  • resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper]
  • Revert environment changes for autoload_paths. [Koz]
  • Update to latest Prototype, which doesn‘t serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs]
  • Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Koz]
  • Added option to script/process/spawner of specifying the binding address 5133 [zsombor]
  • Update environment.rb comments to include config.autoload_paths. Closes 6478 [caio]
  • Update scaffold to use new form_tag block functionality. Closes 6480. [BobSilva]
  • Plugin generator: check for class collisions. 4833 [vinbarnes@gmail.com]
  • Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper]
  • Set $KCODE to ‘u’ by default to enable the multibyte safe String#chars proxy. [Koz]
  • Added config.plugins to control which plugins are loaded 6269 [skaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example:
      config.plugins = %w[ routing_navigator simply_helpful ]
  • Clean up html on included error pages. [Tim Lucas]
  • Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [DHH]
  • Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
  • PostgreSQL: db:test:purge closes open database connections first. 6236 [alex]
  • Fixed test:uncommitted on Windows (backslash issue) 4999 [paul@paulbutcher.com]
  • Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images 6327 [BobSilva]
  • Fixed rename_table on SQLite tables with indexes defined 5942 [brandon@opensoul.org]
  • Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [DHH]
  • Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [DHH]. Examples:
      ./script/generate model post title:string created_on:date body:text published:boolean
  • Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [DHH]
  • script/runner can run files, pass on arguments, and be used as a shebang. 6286 [Tuxie, dlpond]
      #!/usr/bin/env /path/to/my/app/script/runner
  # Example: just start using your models as if you are in script/console
  Product.find(:all).each { |product| product.check_inventory }
  • Look for rake tasks in plugin subdirs. 6259 [obrie]
  • Added map.connect ’:controller/:action/:id.:format’ as a default route to config/routes.rb [DHH]
  • Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson]
    • XPATH support
    • Make Form.getElements() return elements in the correct order
    • fix broken Form.serialize return
  • session_migration generator adds an index on updated_at. 6207 [grg]
  • script/server creates the tmp/pids directory. 6204 [jonathan]
  • Fix script/console —sandbox for internal transactions changes. 5738 [chris@octopod.info, charles.gerungan@gmail.com]
  • Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As

documented in initializer.rb, the workaround is:

  config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/']

References 6031. [Nicholas Seckar]

  • Update to script.aculo.us 1.6.3 [Thomas Fuchs]
  • Update to Prototype 1.5.0_rc1 [sam]
  • Formally Deprecate the old rake tasks. [Koz]
  • Thoroughly test the FCGI dispatcher. 5970 [Kevin Clark]
  • Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson]
  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Cleaning up tests. [Kevin Clark, Jeremy Kemper]
  • Add Dependencies.load_once_paths. [Nicholas Seckar]
  • Updated to script.aculo.us 1.6.2 [Thomas Fuchs]
  • Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar]
  • Don‘t warn dispatcher of Reloadable deprecations. [Nicholas Seckar]
  • Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson]

    ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback.

  • Add missing mock directories from the autoload_paths configuration. [Rick Olson]
  • Nested controller scaffolding also nests the generated layout. [iain d broadfoot]
  • Add "require ‘dispatcher’" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar]
  • Add autoload_paths support to Initializer. [Nicholas Seckar]
  • Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized after Reloadable classes are removed. Closes 5743. [Rick Olson]
  • Clarify usage of script/plugin source. Closes 5344. [james.adam@gmail.com]
  • Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
  • Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed 5279. [Rick Olson]
  • Added that you can change the web server port in config/lighttpd.conf from script/server —port/-p 5465 [mats@imediatec.co.uk]
  • script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. 5679 [shugo@ruby-lang.org]
  • Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson]
  • Make sure script/reaper only reaps dispatcher pids by default, and not the spawner‘s pid. [Jamis Buck]
  • Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam]
  • Dispatcher processes rescued actions with the same controller that processed the request. 4625 [sd@notso.net]
  • rails -d frontbase to create a new project with a frontbase database.yml. 4945 [mlaster@metavillage.com]
  • Ensure the logger is initialized. 5629 [mike@clarkware.com]
  • Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [DHH]. Examples:
      spawner               # starts instances on 8000, 8001, and 8002 using Mongrel if available
  spawner fcgi          # starts instances on 8000, 8001, and 8002 using FCGI
  spawner mongrel -i 5  # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel
  spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available
  spawner -p 9100 -r 5  # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds

    Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster.

  • Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. 5612 [evan@protest.net]
  • db:test:clone should remove existing tables before reloading the schema. 5607 [sveit@tradeharbor.com]
  • Fixed migration generation for class names like ACLController 5197 [brad@madriska.com]
  • Added show_source_list and show_call_stack to breakpoints to make it easier to get context 5476 [takiuchi@drecom.co.jp]. Examples:
      irb(#<TopController:0x40822a68>):002:0> show_source_list
  0001  class TopController < ApplicationController
  0002    def show
  0003->    breakpoint
  0004    end
  0005
  0006    def index
  0007    end
  0008
  => "/path/to/rails/root/app/controllers/top_controller.rb"

  irb(#<TopController:0x40822a68>):004:0> show_call_stack 3
  railties/lib/breakpoint.rb:536:in `breakpoint'
  railties/lib/breakpoint.rb:536:in `breakpoint'
  app/controllers/top_controller.rb:3:in `show'
  => "/path/to/rails/root/app/controllers/top_controller.rb:3"
  • Generate scaffold layout in subdirectory appropriate to its module nesting. 5511 [nils@alumni.rice.edu]
  • Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. 5541 [mike@clarkware.com]
  • Don‘t assume Active Record is available. 5497 [bob@sporkmonger.com]
  • Mongrel: script/server works on Win32. 5499 [jeremydurham@gmail.com]
  • Remove opts.on { |options[:option_name] } style hash assignment. Closes 4440. [nicksieger@gmail.com]
  • Mongrel support for script/server. 5475 [jeremydurham@gmail.com]
  • Fix script/plugin so it doesn‘t barf on invalid URLs [Rick]
  • Fix plugin install bug at dir with space. (closes 5359) [Yoshimasa NIWA]
  • Fix bug with ‘script/plugin install’ so it reports unknown plugin names correctly. [Rick]
  • Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal 5003 [takiuchi@drecom.co.jp]
  • Create temporary dirs relative to RAILS_ROOT when running script/server 5014 [elliot@townx.org]
  • Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck]
  • Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson]
  • Added lib/ to the directories that will get application docs generated [DHH]
  • Add observer generator. Closes 5167. [francois.beausoleil@gmail.com]
  • Session migration generator obeys pluralize_table_names. 5145 [james.adam@gmail.com]
  • rake test:recent understands subdirectories. 2925 [jerrett@bravenet.com]
  • The app generator detects the XAMPP package‘s MySQL socket location. 3832 [elliot@townx.org]
  • The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. 2967 [rcoder, rails-bug@owl.me.uk]
  • Distinguish the spawners for different processes [DHH]
  • Added -n/—process to script/process/spawner name the process pid (default is dispatch) [DHH]
  • Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes 4911) [Julian Tarkhanov]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [DHH]
  • Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [DHH]

*1.2.3* (March 12th, 2007)

  • Ruby 1.8.6 compatibility
  • Windows: include MinGW in RUBY_PLATFORM check. 2982 [okkez000@gmail.com, Kaspar Schiess]
  • Stop swallowing errors during rake test [Koz]

*1.2.2* (February 5th, 2007)

  • Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
  • Require the dispatcher for Rails::Configuration#to_prepare. [Rick]

*1.2.1* (January 16th, 2007)

  • Updated to Active Record 1.15.1, Action Pack 1.13.1, Action Mailer 1.3.1, Action Web Service 1.2.1

*1.2.0* (January 16th, 2007)

  • Update to Prototype 1.5.0. [Sam Stephenson]
  • Generator: use destination path for diff tempfiles. 7015 [alfeld]
  • Fixed that webrick would strip leading newlines and hang connection 4156 [psross]
  • Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick] If you really want your plugins to reload, add this to the very top of init.rb:
      Dependencies.load_once_paths.delete(lib_path)
  • Fix scaffold_resource generator so it respects the —pretend argument when creating the routes file. Closes 6852 [fearoffish]
  • Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes 4899 [Rick Olson]
  • Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam]
  • Don‘t generate a components directory in new Rails apps. [Jeremy Kemper]
  • Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
  • Deprecated the name route "root" as it‘ll be used as a shortcut for map.connect ’’ in Rails 2.0 [DHH]
  • Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
  • Update initializer to load Rails::VERSION as soon as possible. Closes 6698. [Nicholas Seckar]
  • Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won‘t reread the schema if that doesn‘t happen (I‘m looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
  • Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
  • Update to Prototype and script.aculo.us [5579]. [Sam Stephenson, Thomas Fuchs]
  • Made script/server work with -e and -d when using Mongrel [DHH]
  • Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Luetke]
  • Rails::VERSION::STRING should always be available without having to require ‘rails/version’. 6244 [fearoffish]
  • Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck]
  • Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper]
  • Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes 6587. [Nicholas Seckar]
  • Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. 6584 [jchris]
  • scaffold_resource generator uses _path named routes and head instead of render :nothing => true. 6545 [Josh Susser]
  • Generator can show diff on file collision to help you decide whether to skip or overwrite. 6364 [jeffw, Jeremy Kemper]
  • Generated directories are recursively svn added, like mkdir -p. 6416 [NeilW]
  • resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper]
  • Revert environment changes for autoload_paths. [Koz]
  • Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Koz]
  • Added option to script/process/spawner of specifying the binding address 5133 [zsombor]
  • Update environment.rb comments to include config.autoload_paths. Closes 6478 [caio]
  • Update scaffold to use new form_tag block functionality. Closes 6480. [BobSilva]
  • Plugin generator: check for class collisions. 4833 [vinbarnes@gmail.com]
  • Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper]
  • Set $KCODE to ‘u’ by default to enable the multibyte safe String#chars proxy. [Koz]
  • Added config.plugins to control which plugins are loaded 6269 [skaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example:
      config.plugins = %w[ routing_navigator simply_helpful ]
  • Clean up html on included error pages. [Tim Lucas]
  • Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [DHH]
  • Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
  • PostgreSQL: db:test:purge closes open database connections first. 6236 [alex]
  • Fixed test:uncommitted on Windows (backslash issue) 4999 [paul@paulbutcher.com]
  • Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images 6327 [BobSilva]
  • Fixed rename_table on SQLite tables with indexes defined 5942 [brandon@opensoul.org]
  • Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [DHH]
  • Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [DHH]. Examples:
      ./script/generate model post title:string created_on:date body:text published:boolean
  • Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [DHH]
  • script/runner can run files, pass on arguments, and be used as a shebang. 6286 [Tuxie, dlpond]
      #!/usr/bin/env /path/to/my/app/script/runner
  # Example: just start using your models as if you are in script/console
  Product.find(:all).each { |product| product.check_inventory }
  • Look for rake tasks in plugin subdirs. 6259 [obrie]
  • Added map.connect ’:controller/:action/:id.:format’ as a default route to config/routes.rb [DHH]
  • session_migration generator adds an index on updated_at. 6207 [grg]
  • script/server creates the tmp/pids directory. 6204 [jonathan]
  • Fix script/console —sandbox for internal transactions changes. 5738 [chris@octopod.info, charles.gerungan@gmail.com]
  • Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As

documented in initializer.rb, the workaround is:

  config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/']

References 6031. [Nicholas Seckar]

  • Update to script.aculo.us 1.6.3 [Thomas Fuchs]
  • Formally Deprecate the old rake tasks. [Koz]
  • Thoroughly test the FCGI dispatcher. 5970 [Kevin Clark]
  • Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson]
  • Tighten rescue clauses. 5985 [james@grayproductions.net]
  • Cleaning up tests. [Kevin Clark, Jeremy Kemper]
  • Add Dependencies.load_once_paths. [Nicholas Seckar]
  • Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar]
  • Don‘t warn dispatcher of Reloadable deprecations. [Nicholas Seckar]
  • Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson]

    ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback.

  • Add missing mock directories from the autoload_paths configuration. [Rick Olson]
  • Nested controller scaffolding also nests the generated layout. [iain d broadfoot]
  • Add "require ‘dispatcher’" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar]
  • Add autoload_paths support to Initializer. [Nicholas Seckar]
  • Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized after Reloadable classes are removed. Closes 5743. [Rick Olson]
  • Clarify usage of script/plugin source. Closes 5344. [james.adam@gmail.com]
  • Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
  • Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed 5279. [Rick Olson]
  • Added that you can change the web server port in config/lighttpd.conf from script/server —port/-p 5465 [mats@imediatec.co.uk]
  • script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. 5679 [shugo@ruby-lang.org]
  • Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson]
  • Make sure script/reaper only reaps dispatcher pids by default, and not the spawner‘s pid. [Jamis Buck]
  • Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam]
  • Dispatcher processes rescued actions with the same controller that processed the request. 4625 [sd@notso.net]
  • rails -d frontbase to create a new project with a frontbase database.yml. 4945 [mlaster@metavillage.com]
  • Ensure the logger is initialized. 5629 [mike@clarkware.com]
  • Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [DHH]. Examples:
      spawner               # starts instances on 8000, 8001, and 8002 using Mongrel if available
  spawner fcgi          # starts instances on 8000, 8001, and 8002 using FCGI
  spawner mongrel -i 5  # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel
  spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available
  spawner -p 9100 -r 5  # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds

    Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster.

  • Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. 5612 [evan@protest.net]
  • db:test:clone should remove existing tables before reloading the schema. 5607 [sveit@tradeharbor.com]
  • Fixed migration generation for class names like ACLController 5197 [brad@madriska.com]
  • Added show_source_list and show_call_stack to breakpoints to make it easier to get context 5476 [takiuchi@drecom.co.jp]. Examples:
      irb(#<TopController:0x40822a68>):002:0> show_source_list
  0001  class TopController < ApplicationController
  0002    def show
  0003->    breakpoint
  0004    end
  0005
  0006    def index
  0007    end
  0008
  => "/path/to/rails/root/app/controllers/top_controller.rb"

  irb(#<TopController:0x40822a68>):004:0> show_call_stack 3
  railties/lib/breakpoint.rb:536:in `breakpoint'
  railties/lib/breakpoint.rb:536:in `breakpoint'
  app/controllers/top_controller.rb:3:in `show'
  => "/path/to/rails/root/app/controllers/top_controller.rb:3"
  • Generate scaffold layout in subdirectory appropriate to its module nesting. 5511 [nils@alumni.rice.edu]
  • Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. 5541 [mike@clarkware.com]
  • Don‘t assume Active Record is available. 5497 [bob@sporkmonger.com]
  • Mongrel: script/server works on Win32. 5499 [jeremydurham@gmail.com]
  • Remove opts.on { |options[:option_name] } style hash assignment. Closes 4440. [nicksieger@gmail.com]
  • Mongrel support for script/server. 5475 [jeremydurham@gmail.com]
  • Fix script/plugin so it doesn‘t barf on invalid URLs [Rick]
  • Fix plugin install bug at dir with space. (closes 5359) [Yoshimasa NIWA]
  • Fix bug with ‘script/plugin install’ so it reports unknown plugin names correctly. [Rick]
  • Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal 5003 [takiuchi@drecom.co.jp]
  • Create temporary dirs relative to RAILS_ROOT when running script/server 5014 [elliot@townx.org]
  • Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck]
  • Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson]
  • Added lib/ to the directories that will get application docs generated [DHH]
  • Add observer generator. Closes 5167. [francois.beausoleil@gmail.com]
  • Session migration generator obeys pluralize_table_names. 5145 [james.adam@gmail.com]
  • rake test:recent understands subdirectories. 2925 [jerrett@bravenet.com]
  • The app generator detects the XAMPP package‘s MySQL socket location. 3832 [elliot@townx.org]
  • The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. 2967 [rcoder, rails-bug@owl.me.uk]
  • Distinguish the spawners for different processes [DHH]
  • Added -n/—process to script/process/spawner name the process pid (default is dispatch) [DHH]
  • Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes 4911) [Julian Tarkhanov]
  • Replace Ruby‘s deprecated append_features in favor of included. [Marcel Molina Jr.]
  • Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [DHH]
  • Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [DHH]

*1.1.6* (August 10th, 2006)

  • Additional security patch

*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)

  • Mention in docs that config.frameworks doesn‘t work when getting Rails via Gems. Closes 4857. [Alisdair McDiarmid]
  • Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.]
  • 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, 2006)

  • Enhances plugin#discover allowing it to discover svn:// like URIs (closes 4565) [ruben.nine@gmail.com]
  • Update to Prototype 1.5.0_rc0 [Sam Stephenson]
  • Fixed that the -r/—ruby path option of the rails command was not being respected 4549 [ryan.raaum@gmail.com]
  • Added that Dispatcher exceptions should not be shown to the user unless a default log has not been configured. Instead show public/500.html [DHH]
  • Fixed that rake clone_structure_to_test should quit on pgsql if the dump is unsuccesful 4585 [augustz@augustz.com]
  • Fixed that rails —version should have the return code of 0 (success) 4560 [blair@orcaware.com]
  • Install alias so Rails::InfoController is accessible at /rails_info. Closes 4546. [Nicholas Seckar]
  • Fixed that spawner should daemonize if running in repeat mode [DHH]
  • Added TAG option for rake rails:freeze:edge, so you can say rake rails:freeze:edge TAG=rel_1-1-0 to lock to the 1.1.0 release [DHH]
  • Applied Prototype $() performance patches (4465, 4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
  • Use —simple-prompt instead of —prompt-mode simple for console compatibility with Windows/Ruby 1.8.2 4532 [starr@starrnhorne.com]
  • Make Rails::VERSION implicitly loadable 4491. [Nicholas Seckar]
  • Fixed rake rails:freeze:gems 4518 [benji@silverinsanity.com]
  • Added -f/—freeze option to rails command for freezing the application to the Rails version it was generated with [DHH]
  • Added gem binding of apps generated through the rails command to the gems of they were generated with [Nicholas Seckar]
  • Added expiration settings for JavaScript, CSS, HTML, and images to default lighttpd.conf [DHH]
  • Added gzip compression for JavaScript, CSS, and HTML to default lighttpd.conf [DHH]
  • Avoid passing escapeHTML non-string in Rails’ info controller [Nicholas Seckar]

*1.1.0* (March 27th, 2006)

  • Allow db:fixtures:load to load a subset of the applications fixtures. [Chad Fowler]

    ex.

     rake db:fixtures:load FIXTURES=customers,plans
  • Update to Prototype 1.5.0_pre1 [Sam Stephenson]
  • Update to script.aculo.us 1.6 [Thomas Fuchs]
  • Add an integration_test generator [Jamis Buck]
  • Make all ActionView helpers available in the console from the helper method for debugging purposes. n.b.: Only an 80% solution. Some stuff won‘t work, most will. [Marcel Molina Jr.]

    ex.

      >> puts helper.options_for_select([%w(a 1), %w(b 2), %w(c 3)])
  <option value="1">a</option>
  <option value="2">b</option>
  <option value="3">c</option>
  => nil
  • Replaced old session rake tasks with db:sessions:create to generate a migration, and db:sessions:clear to remove sessions. [Rick Olson]
  • Reject Ruby 1.8.3 when loading Rails; extract version checking code. [Chad Fowler]
  • Remove explicit loading of RailsInfo and RailsInfoController. [Nicholas Seckar]
  • Move RailsInfo and RailsInfoController to Rails::Info and Rails::InfoController. [Nicholas Seckar]
  • Extend load path with Railties’ builtin directory to make adding support code easy. [Nicholas Seckar]
  • Fix the rails_info controller by explicitly loading it, and marking it as not reloadable. [Nicholas Seckar]
  • Fixed rails:freeze:gems for Windows 3274 [paul@paulbutcher.com]
  • Added ‘port open?’ check to the spawner when running in repeat mode so we don‘t needlessly boot the dispatcher if the port is already in use anyway 4089 [guy.naor@famundo.com]
  • Add verification to generated scaffolds, don‘t allow get for unsafe actions [Michael Koziarski]
  • Don‘t replace application.js in public/javascripts if it already exists [Cody Fauser]
  • Change test:uncommitted to delay execution of `svn status` by using internal Rake API‘s. [Nicholas Seckar]
  • Use require_library_or_gem to load rake in commands/server.rb. Closes 4205. [rob.rasmussen@gmail.com]
  • Use the Rake API instead of shelling out to create the tmp directory in commands/server.rb. [Chad Fowler]
  • Added a backtrace to the evil WSOD (White Screen of Death). Closes 4073. TODO: Clearer exceptions [Rick Olson]
  • Added tracking of database and framework versions in script/about 4088 [charles.gerungan@gmail.com/Rick Olson]
  • Added public/javascripts/application.js as a sample since it‘ll automatically be included in javascript_include_tag :defaults [DHH]
  • Added socket cleanup for lighttpd, both before and after [DHH]
  • Added automatic creation of tmp/ when running script/server [DHH]
  • Added silence_stream that‘ll work on both STDERR or STDOUT or any other stream and deprecated silence_stderr in the process [DHH]
  • Added reload! method to script/console to reload all models and others that include Reloadable without quitting the console 4056 [esad@esse.at]
  • Added that rake rails:freeze:edge will now just export all the contents of the frameworks instead of just lib, so stuff like rails:update:scripts, rails:update:javascripts, and script/server on lighttpd still just works 4047 [DHH]
  • Added fix for upload problems with lighttpd from Safari/IE to config/lighttpd.conf 3999 [thijs@fngtps.com]
  • Added test:uncommitted to test changes since last checkin to Subversion 4035 [technomancy@gmail.com]
  • Help script/about print the correct svn revision when in a non-English locale. 4026 [babie7a0@ybb.ne.jp]
  • Add ‘app’ accessor to script/console as an instance of Integration::Session [Jamis Buck]
  • Generator::Base#usage takes an optional message argument which defaults to Generator::Base#usage_message. [Jeremy Kemper]
  • Remove the extraneous AR::Base.threaded_connections setting from the webrick server. [Jeremy Kemper]
  • Add integration test support to app generation and testing [Jamis Buck]
  • Added namespaces to all tasks, so for example load_fixtures is now db:fixtures:load. All the old task names are still valid, they just point to the new namespaced names. "rake -T" will only show the namespaced ones, though [DHH]
  • CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by default instead of :sql. This means that we‘ll assume you want to live in the world of db/schema.rb where the grass is green and the girls are pretty. If your schema contains un-dumpable elements, such as constraints or database-specific column types, you just got an invitation to either 1) patch the dumper to include foreign key support, 2) stop being db specific, or 3) just change the default in config/environment.rb to config.active_record.schema_format = :sql — we even include an example for that on new Rails skeletons now. Brought to you by the federation of opinionated framework builders! [DHH]
  • Added -r/—repeat option to script/process/spawner that offers the same loop protection as the spinner did. This deprecates the script/process/spinner, so it‘s no longer included in the default Rails skeleton, but still available for backwards compatibility 3461 [ror@andreas-s.net]
  • Added collision option to template generation in generators 3329 [anna@wota.jp]. Examples:
      m.template "stuff.config" , "config/stuff.config" , :collision => :skip
  m.template "auto-stamping", "config/generator.log", :collision => :force
  • Added more information to script/plugin‘s doings to ease debugging 3755 [Rick Olson]
  • Changed the default configuration for lighttpd to use tmp/sockets instead of log/ for the FastCGI sockets [DHH]
  • Added a default configuration of the FileStore for fragment caching if tmp/cache is available, which makes action/fragment caching ready to use out of the box with no additional configuration [DHH]
  • Changed the default session configuration to place sessions in tmp/sessions, if that directory is available, instead of /tmp (this essentially means a goodbye to 9/10 White Screen of Death errors and should have web hosting firms around the world cheering) [DHH]
  • Added tmp/sessions, tmp/cache, and tmp/sockets as default directories in the Rails skeleton [DHH]
  • Added that script/generate model will now automatically create a migration file for the model created. This can be turned off by calling the generator with —skip-migration [DHH]
  • Added -d/—database option to the rails command, so you can do "rails —database=sqlite2 myapp" to start a new application preconfigured to use SQLite2 as the database. Removed the configuration examples from SQLite and PostgreSQL from the default MySQL configuration [DHH]
  • Allow script/server -c /path/to/lighttpd.conf [Jeremy Kemper]
  • Remove hardcoded path to reaper script in script/server [Jeremy Kemper]
  • Update script.aculo.us to V1.5.3 [Thomas Fuchs]
  • Added SIGTRAP signal handler to RailsFCGIHandler that‘ll force the process into a breakpoint after the next request. This breakpoint can then be caught with script/breakpointer and give you access to the Ruby image inside that process. Useful for debugging memory leaks among other things [DHH]
  • Changed default lighttpd.conf to use CWD from lighttpd 1.4.10 that allows the same configuration to be used for both detach and not. Also ensured that auto-repeaping of FCGIs only happens when lighttpd is not detached. [DHH]
  • Added Configuration#after_initialize for registering a block which gets called after the framework is fully initialized. Useful for things like per-environment configuration of plugins. [Michael Koziarski]
  • Added check for RAILS_FRAMEWORK_ROOT constant that allows the Rails framework to be found in a different place than vendor/rails. Should be set in boot.rb. [DHH]
  • Fixed that static requests could unlock the mutex guarding dynamic requests in the WEBrick servlet 3433 [tom@craz8.com]
  • Fixed documentation tasks to work with Rake 0.7.0 3563 [kazuhiko@fdiary.net]
  • Update to Prototype 1.5.0_pre0 [Sam Stephenson]
  • Sort the list of plugins so we load in a consistent order [Rick Olson]
  • Show usage when script/plugin is called without arguments [tom@craz8.com]
  • Corrected problems with plugin loader where plugins set ‘name’ incorrectly 3297 [anna@wota.jp]
  • Make migration generator only report on exact duplicate names, not partial dupliate names. 3442 [jeremy@planetargon.com Marcel Molina Jr.]
  • Fix typo in mailer generator USAGE. 3458 [chriztian.steinmeier@gmail.com]
  • Ignore version mismatch between pg_dump and the database server. 3457 [simon.stapleton@gmail.com]
  • Reap FCGI processes after lighttpd exits. [Sam Stephenson]
  • 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]
  • Generator looks in vendor/generators also. [Chad Fowler]
  • Generator copies files in binary mode. 3156 [minimudboy@gmail.com]
  • Add builtin/ to the gemspec. Closes 3047. [Nicholas Seckar, Sam Stephenson]
  • Add install.rb file to plugin generation which is loaded, if it exists, when you install a plugin. [Marcel Molina Jr.]
  • Run initialize_logger in script/lighttpd to ensure the log file exists before tailing it. [Sam Stephenson]
  • Make load_fixtures include csv fixtures. 3053. [me@mdaines.com]
  • Fix freeze_gems so that the latest rails version is dumped by default. [Nicholas Seckar]
  • script/plugin: handle root paths and plugin names which contain spaces. 2995 [justin@aspect.net]
  • Model generator: correct relative path to test_helper in unit test. [Jeremy Kemper]
  • Make the db_schema_dump task honor the SCHEMA environment variable if present the way db_schema_import does. 2931. [Blair Zajac]
  • Have the lighttpd server script report the actual ip to which the server is bound. 2903. [Adam]
  • Add plugin library directories to the load path after the lib directory so that libraries in the lib directory get precedence. 2910. [james.adam@gmail.com]
  • Make help for the console command more explicit about how to specify the desired environment in which to run the console. 2911. [anonymous]
  • PostgreSQL: the purge_test_database Rake task shouldn‘t explicitly specify the template0 template when creating a fresh test database. 2964 [dreamer3@gmail.com]
  • Introducing the session_migration generator. Creates an add_session_table migration. Allows generator to specify migrations directory. 2958, 2960 [Rick Olson]
  • script/console uses RAILS_ENV environment variable if present. 2932 [Blair Zajac <blair@orcaware.com>
  • Windows: eliminate the socket option in database.yml. 2924 [Wayne Vucenic <waynev@gmail.com>]
  • Eliminate nil from newly generated logfiles. 2927 [Blair Zajac <blair@orcaware.com>]
  • Rename Version constant to VERSION. 2802 [Marcel Molina Jr.]
  • Eliminate Subversion dependencies in scripts/plugin. Correct install options. Introduce —force option to reinstall a plugin. Remove useless —long option for list. Use —quiet to quiet the download output and —revision to update to a specific svn revision. 2842 [Chad Fowler, Rick Olson]
  • SQLite: the clone_structure_to_test and purge_test_database Rake tasks should always use the test environment. 2846 [Rick Olson]
  • Make sure that legacy db tasks also reference :database for SQLite 2830 [kazuhiko@fdiary.net]
  • Pass FILE when evaluating plugins’ init.rb. 2817 [james.adam@gmail.com]
  • Better svn status matching for generators. 2814 [François Beausoleil <francois.beausoleil@gmail.com>, Blair Zajac <blair@orcaware.com>]
  • Don‘t reload routes until plugins have been loaded so they have a chance to extend the routing capabilities [DHH]
  • Don‘t detach or fork for script/server tailing [Nicholas Seckar]
  • Changed all script/* to use #!/usr/bin/env ruby instead of hard-coded Ruby path. public/dispatcher.* still uses the hard-coded path for compatibility with web servers that don‘t have Ruby in path [DHH]
  • Force RAILS_ENV to be "test" when running tests, so that ENV["RAILS_ENV"] = "production" in config/environment.rb doesn‘t wreck havok [DHH] 2660
  • Correct versioning in :freeze_gems Rake task. 2778 [jakob@mentalized.net, Jeremy Kemper]
  • Added an omnipresent RailsInfoController with a properties action that delivers an HTML rendering of Rails::Info (but only when local_request? is true). Added a new default index.html which fetches this with Ajax. [Sam Stephenson]

*0.14.3 (RC4)* (November 7th, 2005)

  • Add ‘add_new_scripts’ rake task for adding new rails scripts to script/* [Jamis Buck]
  • Remove bogus hyphen from script/process/reaper calls to ‘ps’. 2767 [anonymous]
  • Copy lighttpd.conf when it is first needed, instead of on app creation [Jamis Buck]
  • Use require_library_or_gem ‘fcgi’ in script/server [Sam Stephenson]
  • Added default lighttpd config in config/lighttpd.conf and added a default runner for lighttpd in script/server (works like script/server, but using lighttpd and FastCGI). It will use lighttpd if available, otherwise WEBrick. You can force either or using ‘script/server lighttpd’ or ‘script/server webrick’ [DHH]
  • New configuration option config.plugin_paths which may be a single path like the default ‘vendor/plugins’ or an array of paths: [‘vendor/plugins’, ‘lib/plugins’]. [Jeremy Kemper]
  • Plugins are discovered in nested paths, so you can organize your plugins directory as you like. [Jeremy Kemper]
  • Refactor load_plugin from load_plugins. 2757 [alex.r.moon@gmail.com]
  • Make use of silence_stderr in script/lighttpd, script/plugin, and Rails::Info [Sam Stephenson]
  • Enable HTTP installation of plugins when svn isn‘t avaialable. Closes 2661. [Chad Fowler]
  • Added script/about to display formatted Rails::Info output [Sam Stephenson]
  • Added Rails::Info to catalog assorted information about a Rails application‘s environment [Sam Stephenson]
  • Tail the logfile when running script/server lighttpd in the foreground [Sam Stephenson]
  • Try to guess the port number from config/lighttpd.conf in script/server lighttpd [Sam Stephenson]
  • Don‘t reap spawn-fcgi. 2727 [matthew@walker.wattle.id.au]
  • Reaper knows how to find processes even if the dispatch path is very long. 2711 [matthew@walker.wattle.id.au]
  • Make fcgi handler respond to TERM signals with an explicit exit [Jamis Buck]
  • Added demonstration of fixture use to the test case generated by the model generator [DHH]
  • If specified, pass PostgreSQL client character encoding to createdb. 2703 [Kazuhiko <kazuhiko@fdiary.net>]
  • Catch CGI multipart parse errors. Wrap dispatcher internals in a failsafe response handler. [Jeremy Kemper]
  • The freeze_gems Rake task accepts the VERSION environment variable to decide which version of Rails to pull into vendor/rails. [Chad Fowler, Jeremy Kemper]
  • Removed script.aculo.us.js, builder.js and slider.js (preperation for move of scriptaculous extensions to plugins, core scriptaculous will remain in Railties) [Thomas Fuchs]
  • The freeze_edge Rake task does smarter svn detection and can export a specific revision by passing the REVISION environment variable. For example: rake freeze_edge REVISION=1234. 2663 [Rick Olson]
  • Comment database.yml and include PostgreSQL and SQLite examples. [Jeremy Kemper]
  • Improve script/plugin on Windows. 2646 [Chad Fowler]
  • The *_plugindoc Rake tasks look deeper into the plugins’ lib directories. 2652 [bellis@deepthought.org]
  • The PostgreSQL :db_structure_dump Rake task limits its dump to the schema search path in database.yml. [Anatol Pomozov <anatol.pomozov@gmail.com>]
  • Add task to generate rdoc for all installed plugins. [Marcel Molina]
  • Update script.aculo.us to V1.5_rc4 [Thomas Fuchs]
  • Add default Mac + DarwinPorts MySQL socket locations to the app generator. [Jeremy Kemper]
  • Migrations may be destroyed: script/destroy migration foo. 2635 [Charles M. Gerungan <charles.gerungan@gmail.com>, Jamis Buck, Jeremy Kemper]
  • Added that plugins can carry generators and that generator stub files can be created along with new plugins using script/generate plugin <name> —with-generator [DHH]
  • Removed app/apis as a default empty dir since its automatically created when using script/generate web_service [DHH]
  • Added script/plugin to manage plugins (install, remove, list, etc) [Ryan Tomayko]
  • Added test_plugins task: Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name) [DHH]
  • Added plugin generator to create a stub structure for a new plugin in vendor/plugins (see "script/generate plugin" for help) [DHH]
  • Fixed scaffold generator when started with only 1 parameter 2609 [self@mattmower.com]
  • rake should run functional tests even if the unit tests have failures [Jim Weirich]
  • Back off cleanpath to be symlink friendly. Closes 2533 [Nicholas Seckar]
  • Load rake task files in alphabetical order so you can build dependencies and count on them 2554 [Blair Zajac]

*0.14.2 (RC3)* (October 26th, 2005)

  • Constants set in the development/test/production environment file are set in Object
  • Scaffold generator pays attention to the controller name. 2562 [self@mattmower.com]
  • Include tasks from vendor/plugins/*/tasks in the Rakefile 2545 [Rick Olson]

*0.14.1 (RC2)* (October 19th, 2005)

  • Don‘t clean RAILS_ROOT on windows
  • Remove trailing ’/’ from RAILS_ROOT [Nicholas Seckar]
  • Upgraded to Active Record 1.12.1 and Action Pack 1.10.1

*0.14.0 (RC1)* (October 16th, 2005)

  • Moved generator folder from RAILS_ROOT/generators to RAILS_ROOT/lib/generators [Tobias Luetke]
  • Fix rake dev and related commands [Nicholas Seckar]
  • The rails command tries to deduce your MySQL socket by running `mysql_config