提交 f638ef95 编写于 作者: V Vijay Dev

Merge branch 'master' of github.com:lifo/docrails

Conflicts:
	activerecord/lib/active_record/persistence.rb
	railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
...@@ -83,7 +83,7 @@ Note that every value you set with this method will get over written if you use ...@@ -83,7 +83,7 @@ Note that every value you set with this method will get over written if you use
Example: Example:
class AuthenticationMailer < ActionMailer::Base class AuthenticationMailer < ActionMailer::Base
default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" } default from: "awesome@application.com", subject: Proc.new { "E-mail was generated at #{Time.now}" }
..... .....
end end
...@@ -100,13 +100,13 @@ Example: ...@@ -100,13 +100,13 @@ Example:
def receive(email) def receive(email)
page = Page.find_by_address(email.to.first) page = Page.find_by_address(email.to.first)
page.emails.create( page.emails.create(
:subject => email.subject, :body => email.body subject: email.subject, body: email.body
) )
if email.has_attachments? if email.has_attachments?
email.attachments.each do |attachment| email.attachments.each do |attachment|
page.attachments.create({ page.attachments.create({
:file => attachment, :description => email.subject file: attachment, description: email.subject
}) })
end end
end end
...@@ -127,11 +127,11 @@ a limited number of email. ...@@ -127,11 +127,11 @@ a limited number of email.
The Base class has the full list of configuration options. Here's an example: The Base class has the full list of configuration options. Here's an example:
ActionMailer::Base.smtp_settings = { ActionMailer::Base.smtp_settings = {
:address => 'smtp.yourserver.com', # default: localhost address: 'smtp.yourserver.com', # default: localhost
:port => '25', # default: 25 port: '25', # default: 25
:user_name => 'user', user_name: 'user',
:password => 'pass', password: 'pass',
:authentication => :plain # :plain, :login or :cram_md5 authentication: :plain # :plain, :login or :cram_md5
} }
......
...@@ -6,7 +6,7 @@ module ActionDispatch ...@@ -6,7 +6,7 @@ module ActionDispatch
# and calls an exceptions app that will wrap it in a format for the end user. # and calls an exceptions app that will wrap it in a format for the end user.
# #
# The exceptions app should be passed as parameter on initialization # The exceptions app should be passed as parameter on initialization
# of ShowExceptions. Everytime there is an exception, ShowExceptions will # of ShowExceptions. Every time there is an exception, ShowExceptions will
# store the exception in env["action_dispatch.exception"], rewrite the # store the exception in env["action_dispatch.exception"], rewrite the
# PATH_INFO to the exception status code and call the rack app. # PATH_INFO to the exception status code and call the rack app.
# #
......
...@@ -160,7 +160,7 @@ module HTML ...@@ -160,7 +160,7 @@ module HTML
# * <tt>:not(selector)</tt> -- Match the element only if the element does not # * <tt>:not(selector)</tt> -- Match the element only if the element does not
# match the simple selector. # match the simple selector.
# #
# As you can see, <tt>:nth-child<tt> pseudo class and its variant can get quite # As you can see, <tt>:nth-child</tt> pseudo class and its variant can get quite
# tricky and the CSS specification doesn't do a much better job explaining it. # 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 # But after reading the examples and trying a few combinations, it's easy to
# figure out. # figure out.
......
...@@ -23,7 +23,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>. ...@@ -23,7 +23,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>.
validates_presence_of :name validates_presence_of :name
end end
person = Person.new(:name => 'bob', :age => '18') person = Person.new(name: 'bob', age: '18')
person.name # => 'bob' person.name # => 'bob'
person.age # => '18' person.age # => '18'
person.valid? # => true person.valid? # => true
......
...@@ -190,10 +190,10 @@ def association_instance_set(name, association) ...@@ -190,10 +190,10 @@ def association_instance_set(name, association)
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt> # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt> # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt> # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
# <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.all(options),</tt> # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(mileston), Project#milestones.find(milestone_id),</tt>
# <tt>Project#milestones.build, Project#milestones.create</tt> # <tt>Project#milestones.all(options), Project#milestones.build, Project#milestones.create</tt>
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt> # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
# <tt>Project#categories.delete(category1)</tt> # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
# #
# === A word of warning # === A word of warning
# #
...@@ -236,6 +236,7 @@ def association_instance_set(name, association) ...@@ -236,6 +236,7 @@ def association_instance_set(name, association)
# others.clear | X | X | X # others.clear | X | X | X
# others.delete(other,other,...) | X | X | X # others.delete(other,other,...) | X | X | X
# others.delete_all | X | X | X # others.delete_all | X | X | X
# others.destroy(other,other,...) | X | X | X
# others.destroy_all | X | X | X # others.destroy_all | X | X | X
# others.find(*args) | X | X | X # others.find(*args) | X | X | X
# others.exists? | X | X | X # others.exists? | X | X | X
...@@ -1031,6 +1032,12 @@ module ClassMethods ...@@ -1031,6 +1032,12 @@ module ClassMethods
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than # If the <tt>:through</tt> option is used, then the join records are deleted (rather than
# nullified) by default, but you can specify <tt>:dependent => :destroy</tt> or # nullified) by default, but you can specify <tt>:dependent => :destroy</tt> or
# <tt>:dependent => :nullify</tt> to override this. # <tt>:dependent => :nullify</tt> to override this.
# [collection.destroy(object, ...)]
# Removes one or more objects from the collection by running <tt>destroy</tt> on
# each record, regardless of any dependent option, ensuring callbacks are run.
#
# If the <tt>:through</tt> option is used, then the join records are destroyed
# instead, not the objects themselves.
# [collection=objects] # [collection=objects]
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt> # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
...@@ -1074,6 +1081,7 @@ module ClassMethods ...@@ -1074,6 +1081,7 @@ module ClassMethods
# * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</tt>) # * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</tt>)
# * <tt>Firm#clients<<</tt> # * <tt>Firm#clients<<</tt>
# * <tt>Firm#clients.delete</tt> # * <tt>Firm#clients.delete</tt>
# * <tt>Firm#clients.destroy</tt>
# * <tt>Firm#clients=</tt> # * <tt>Firm#clients=</tt>
# * <tt>Firm#client_ids</tt> # * <tt>Firm#client_ids</tt>
# * <tt>Firm#client_ids=</tt> # * <tt>Firm#client_ids=</tt>
...@@ -1425,6 +1433,9 @@ def belongs_to(name, scope = nil, options = {}) ...@@ -1425,6 +1433,9 @@ def belongs_to(name, scope = nil, options = {})
# [collection.delete(object, ...)] # [collection.delete(object, ...)]
# Removes one or more objects from the collection by removing their associations from the join table. # Removes one or more objects from the collection by removing their associations from the join table.
# This does not destroy the objects. # This does not destroy the objects.
# [collection.destroy(object, ...)]
# Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
# This does not destroy the objects.
# [collection=objects] # [collection=objects]
# Replaces the collection's content by deleting and adding objects as appropriate. # Replaces the collection's content by deleting and adding objects as appropriate.
# [collection_singular_ids] # [collection_singular_ids]
...@@ -1461,6 +1472,7 @@ def belongs_to(name, scope = nil, options = {}) ...@@ -1461,6 +1472,7 @@ def belongs_to(name, scope = nil, options = {})
# * <tt>Developer#projects</tt> # * <tt>Developer#projects</tt>
# * <tt>Developer#projects<<</tt> # * <tt>Developer#projects<<</tt>
# * <tt>Developer#projects.delete</tt> # * <tt>Developer#projects.delete</tt>
# * <tt>Developer#projects.destroy</tt>
# * <tt>Developer#projects=</tt> # * <tt>Developer#projects=</tt>
# * <tt>Developer#project_ids</tt> # * <tt>Developer#project_ids</tt>
# * <tt>Developer#project_ids=</tt> # * <tt>Developer#project_ids=</tt>
......
...@@ -241,7 +241,7 @@ def simplified_type(field_type) ...@@ -241,7 +241,7 @@ def simplified_type(field_type)
# <encoding></tt> call on the connection. # <encoding></tt> call on the connection.
# * <tt>:min_messages</tt> - An optional client min messages that is used in a # * <tt>:min_messages</tt> - An optional client min messages that is used in a
# <tt>SET client_min_messages TO <min_messages></tt> call on the connection. # <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT<tt> statements # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT</tt> statements
# defaults to true. # defaults to true.
# #
# Any further options are used as connection parameters to libpq. See # Any further options are used as connection parameters to libpq. See
......
...@@ -50,7 +50,7 @@ def initialize ...@@ -50,7 +50,7 @@ def initialize
# #
# class AddSsl < ActiveRecord::Migration # class AddSsl < ActiveRecord::Migration
# def up # def up
# add_column :accounts, :ssl_enabled, :boolean, :default => true # add_column :accounts, :ssl_enabled, :boolean, default: true
# end # end
# #
# def down # def down
...@@ -62,7 +62,7 @@ def initialize ...@@ -62,7 +62,7 @@ def initialize
# if you're backing out of the migration. It shows how all migrations have # if you're backing out of the migration. It shows how all migrations have
# two methods +up+ and +down+ that describes the transformations # two methods +up+ and +down+ that describes the transformations
# required to implement or remove the migration. These methods can consist # required to implement or remove the migration. These methods can consist
# of both the migration specific methods like add_column and remove_column, # 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 # but may also contain regular Ruby code for generating data needed for the
# transformations. # transformations.
# #
...@@ -78,9 +78,9 @@ def initialize ...@@ -78,9 +78,9 @@ def initialize
# t.integer :position # t.integer :position
# end # end
# #
# SystemSetting.create :name => "notice", # SystemSetting.create name: 'notice',
# :label => "Use notice?", # label: 'Use notice?',
# :value => 1 # value: 1
# end # end
# #
# def down # def down
...@@ -88,19 +88,22 @@ def initialize ...@@ -88,19 +88,22 @@ def initialize
# end # end
# end # end
# #
# This migration first adds the system_settings table, then creates the very # 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 # 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 # also uses the more advanced +create_table+ syntax where you can specify a
# complete table schema in one block call. # complete table schema in one block call.
# #
# == Available transformations # == Available transformations
# #
# * <tt>create_table(name, options)</tt> Creates a table called +name+ and # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
# makes the table object available to a block that can then add columns to it, # 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 # 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 # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
# table definition. # table definition.
# * <tt>drop_table(name)</tt>: Drops the table called +name+. # * <tt>drop_table(name)</tt>: Drops the table called +name+.
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
# the table called +name+. It makes the table object availabe to a block that
# can then add/remove columns, indexes or foreign keys to it.
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
# to +new_name+. # to +new_name+.
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
...@@ -109,9 +112,9 @@ def initialize ...@@ -109,9 +112,9 @@ def initialize
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
# <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>, # <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
# specified by passing an +options+ hash like <tt>{ :default => 11 }</tt>. # specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g. # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
# <tt>{ :limit => 50, :null => false }</tt>) -- see # <tt>{ limit: 50, null: false }</tt>) -- see
# ActiveRecord::ConnectionAdapters::TableDefinition#column for details. # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
# a column but keeps the type and content. # a column but keeps the type and content.
...@@ -122,11 +125,11 @@ def initialize ...@@ -122,11 +125,11 @@ def initialize
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
# with the name of the column. Other options include # with the name of the column. Other options include
# <tt>:name</tt>, <tt>:unique</tt> (e.g. # <tt>:name</tt>, <tt>:unique</tt> (e.g.
# <tt>{ :name => "users_name_index", :unique => true }</tt>) and <tt>:order</tt> # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
# (e.g. { :order => {:name => :desc} }</tt>). # (e.g. <tt>{ order: { name: :desc } }</tt>).
# * <tt>remove_index(table_name, :column => column_name)</tt>: Removes the index # * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
# specified by +column_name+. # specified by +column_name+.
# * <tt>remove_index(table_name, :name => index_name)</tt>: Removes the index # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
# specified by +index_name+. # specified by +index_name+.
# #
# == Irreversible transformations # == Irreversible transformations
......
...@@ -197,7 +197,7 @@ def update_attributes!(attributes) ...@@ -197,7 +197,7 @@ def update_attributes!(attributes)
end end
end end
# Updates a single attribute of an object, without having to call save on that object. # Updates a single attribute of an object, without having to explicitly call save on that object.
# #
# * Validation is skipped. # * Validation is skipped.
# * Callbacks are skipped. # * Callbacks are skipped.
...@@ -209,7 +209,7 @@ def update_column(name, value) ...@@ -209,7 +209,7 @@ def update_column(name, value)
update_columns(name => value) update_columns(name => value)
end end
# Updates the attributes from the passed-in hash, without having to call save on that object. # Updates the attributes from the passed-in hash, without having to explicitly call save on that object.
# #
# * Validation is skipped. # * Validation is skipped.
# * Callbacks are skipped. # * Callbacks are skipped.
......
...@@ -40,7 +40,7 @@ def find_each(options = {}) ...@@ -40,7 +40,7 @@ def find_each(options = {})
# #
# It's not possible to set the order. That is automatically set to # It's not possible to set the order. That is automatically set to
# ascending on the primary key ("id ASC") to make the batch ordering # ascending on the primary key ("id ASC") to make the batch ordering
# work. This also mean that this method only works with integer-based # work. This also means that this method only works with integer-based
# primary keys. You can't set the limit either, that's used to control # primary keys. You can't set the limit either, that's used to control
# the batch sizes. # the batch sizes.
# #
......
...@@ -156,7 +156,7 @@ def test_has_many_association_updating_a_single_record ...@@ -156,7 +156,7 @@ def test_has_many_association_updating_a_single_record
end end
def test_reject_if_with_blank_nested_attributes_id def test_reject_if_with_blank_nested_attributes_id
# When using a select list to choose an existing 'ship' id, with :include_blank => true # When using a select list to choose an existing 'ship' id, with include_blank: true
Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? } Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? }
pirate = Pirate.new(:catchphrase => "Stop wastin' me time") pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
......
...@@ -43,7 +43,7 @@ def replied_topic ...@@ -43,7 +43,7 @@ def replied_topic
[ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }] [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }]
# TODO Add :on case, but below doesn't work, because then the validation isn't run for some reason # TODO Add :on case, but below doesn't work, because then the validation isn't run for some reason
# even when using .save instead .valid? # even when using .save instead .valid?
# [ "given on condition", {:on => :save}, {}] # [ "given on condition", {on: :save}, {}]
] ]
# validates_uniqueness_of w/ mocha # validates_uniqueness_of w/ mocha
......
...@@ -476,7 +476,7 @@ The following configuration options are best made in one of the environment file ...@@ -476,7 +476,7 @@ The following configuration options are best made in one of the environment file
|`logger`|Generates 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.| |`logger`|Generates 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:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`: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`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>| |`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`: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`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>|
|`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>| |`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>|
|`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered.| |`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.|
|`delivery_method`|Defines a delivery method. Possible values are `:smtp` (default), `:sendmail`, `:file` and `:test`.| |`delivery_method`|Defines a delivery method. Possible values are `:smtp` (default), `:sendmail`, `:file` and `:test`.|
|`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| |`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. 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.| |`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.|
......
...@@ -375,8 +375,6 @@ end ...@@ -375,8 +375,6 @@ end
Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:start` option on each worker. Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:start` option on each worker.
NOTE: The `:include` option allows you to name associations that should be loaded alongside with the models.
#### `find_in_batches` #### `find_in_batches`
The `find_in_batches` method is similar to `find_each`, since both retrieve batches of records. The difference is that `find_in_batches` yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices: The `find_in_batches` method is similar to `find_each`, since both retrieve batches of records. The difference is that `find_in_batches` yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices:
......
...@@ -50,6 +50,7 @@ end ...@@ -50,6 +50,7 @@ end
We can see how it works by looking at some `rails console` output: We can see how it works by looking at some `rails console` output:
```ruby ```ruby
$ rails console
>> p = Person.new(:name => "John Doe") >> p = Person.new(:name => "John Doe")
=> #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil> => #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil>
>> p.new_record? >> p.new_record?
...@@ -60,6 +61,8 @@ We can see how it works by looking at some `rails console` output: ...@@ -60,6 +61,8 @@ We can see how it works by looking at some `rails console` output:
=> false => false
``` ```
TIP: All lines starting with a dollar sign `$` are intended to be run on the command line.
Creating and saving a new record will send an SQL `INSERT` operation to the database. Updating an existing record will send an SQL `UPDATE` operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the `INSERT` or `UPDATE` operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. Creating and saving a new record will send an SQL `INSERT` operation to the database. Updating an existing record will send an SQL `UPDATE` operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the `INSERT` or `UPDATE` operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated.
CAUTION: There are many ways to change the state of an object in the database. Some methods will trigger validations, but some will not. This means that it's possible to save an object in the database in an invalid state if you aren't careful. CAUTION: There are many ways to change the state of an object in the database. Some methods will trigger validations, but some will not. This means that it's possible to save an object in the database in an invalid state if you aren't careful.
......
...@@ -1130,6 +1130,7 @@ When you declare a `has_many` association, the declaring class automatically gai ...@@ -1130,6 +1130,7 @@ When you declare a `has_many` association, the declaring class automatically gai
* `collection(force_reload = false)` * `collection(force_reload = false)`
* `collection<<(object, ...)` * `collection<<(object, ...)`
* `collection.delete(object, ...)` * `collection.delete(object, ...)`
* `collection.destroy(object, ...)`
* `collection=objects` * `collection=objects`
* `collection_singular_ids` * `collection_singular_ids`
* `collection_singular_ids=ids` * `collection_singular_ids=ids`
...@@ -1156,6 +1157,7 @@ Each instance of the customer model will have these methods: ...@@ -1156,6 +1157,7 @@ Each instance of the customer model will have these methods:
orders(force_reload = false) orders(force_reload = false)
orders<<(object, ...) orders<<(object, ...)
orders.delete(object, ...) orders.delete(object, ...)
orders.destroy(object, ...)
orders=objects orders=objects
order_ids order_ids
order_ids=ids order_ids=ids
...@@ -1195,6 +1197,15 @@ The `collection.delete` method removes one or more objects from the collection b ...@@ -1195,6 +1197,15 @@ The `collection.delete` method removes one or more objects from the collection b
WARNING: Additionally, objects will be destroyed if they're associated with `:dependent => :destroy`, and deleted if they're associated with `:dependent => :delete_all`. WARNING: Additionally, objects will be destroyed if they're associated with `:dependent => :destroy`, and deleted if they're associated with `:dependent => :delete_all`.
##### `collection.destroy(object, ...)`
The `collection.destroy` method removes one or more objects from the collection by running `destroy` on each object.
```ruby
@customer.orders.destroy(@order1)
```
WARNING: Objects will _always_ be removed from the database, ignoring the `:dependent` option.
##### `collection=objects` ##### `collection=objects`
...@@ -1564,6 +1575,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au ...@@ -1564,6 +1575,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au
* `collection(force_reload = false)` * `collection(force_reload = false)`
* `collection<<(object, ...)` * `collection<<(object, ...)`
* `collection.delete(object, ...)` * `collection.delete(object, ...)`
* `collection.destroy(object, ...)`
* `collection=objects` * `collection=objects`
* `collection_singular_ids` * `collection_singular_ids`
* `collection_singular_ids=ids` * `collection_singular_ids=ids`
...@@ -1590,6 +1602,7 @@ Each instance of the part model will have these methods: ...@@ -1590,6 +1602,7 @@ Each instance of the part model will have these methods:
assemblies(force_reload = false) assemblies(force_reload = false)
assemblies<<(object, ...) assemblies<<(object, ...)
assemblies.delete(object, ...) assemblies.delete(object, ...)
assemblies.destroy(object, ...)
assemblies=objects assemblies=objects
assembly_ids assembly_ids
assembly_ids=ids assembly_ids=ids
...@@ -1636,6 +1649,16 @@ The `collection.delete` method removes one or more objects from the collection b ...@@ -1636,6 +1649,16 @@ The `collection.delete` method removes one or more objects from the collection b
@part.assemblies.delete(@assembly1) @part.assemblies.delete(@assembly1)
``` ```
WARNING: This does not trigger callbacks on the join records.
##### `collection.destroy(object, ...)`
The `collection.destroy` method removes one or more objects from the collection by running `destroy` on each record in the join table, including running callbacks. This does not destroy the objects.
```ruby
@part.assemblies.destroy(@assembly1)
```
##### `collection=objects` ##### `collection=objects`
The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
......
...@@ -5,17 +5,20 @@ This guide will teach you what you need to know about avoiding that expensive ro ...@@ -5,17 +5,20 @@ This guide will teach you what you need to know about avoiding that expensive ro
After reading this guide, you should be able to use and configure: After reading this guide, you should be able to use and configure:
* Page, action, and fragment caching * Page, action, and fragment caching.
* Sweepers * Sweepers.
* Alternative cache stores * Alternative cache stores.
* Conditional GET support * Conditional GET support.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Basic Caching Basic Caching
------------- -------------
This is an introduction to the three types of caching techniques that Rails provides by default without the use of any third party plugins. This is an introduction to three types of caching techniques: page, action and
fragment caching. Rails provides by default fragment caching. In order to use
page and action caching, you will need to add `actionpack-page_caching` and
`actionpack-action_caching` to your Gemfile.
To start playing with caching you'll want to ensure that `config.action_controller.perform_caching` is set to `true`, if you're running in development mode. This flag is normally set in the corresponding `config/environments/*.rb` and caching is disabled by default for development and test, and enabled for production. To start playing with caching you'll want to ensure that `config.action_controller.perform_caching` is set to `true`, if you're running in development mode. This flag is normally set in the corresponding `config/environments/*.rb` and caching is disabled by default for development and test, and enabled for production.
...@@ -44,7 +47,7 @@ Let's say you have a controller called `ProductsController` and an `index` actio ...@@ -44,7 +47,7 @@ Let's say you have a controller called `ProductsController` and an `index` actio
By default, the page cache directory is set to `Rails.public_path` (which is usually set to the `public` folder) and this can be configured by changing the configuration setting `config.action_controller.page_cache_directory`. Changing the default from `public` helps avoid naming conflicts, since you may want to put other static html in `public`, but changing this will require web server reconfiguration to let the web server know where to serve the cached files from. By default, the page cache directory is set to `Rails.public_path` (which is usually set to the `public` folder) and this can be configured by changing the configuration setting `config.action_controller.page_cache_directory`. Changing the default from `public` helps avoid naming conflicts, since you may want to put other static html in `public`, but changing this will require web server reconfiguration to let the web server know where to serve the cached files from.
The Page Caching mechanism will automatically add a `.html` extension to requests for pages that do not have an extension to make it easy for the webserver to find those pages and this can be configured by changing the configuration setting `config.action_controller.page_cache_extension`. The Page Caching mechanism will automatically add a `.html` extension to requests for pages that do not have an extension to make it easy for the webserver to find those pages and this can be configured by changing the configuration setting `config.action_controller.default_static_extension`.
In order to expire this page when a new product is added we could extend our example controller like this: In order to expire this page when a new product is added we could extend our example controller like this:
......
...@@ -282,12 +282,8 @@ config.middleware.delete ActionDispatch::BestStandardsSupport ...@@ -282,12 +282,8 @@ config.middleware.delete ActionDispatch::BestStandardsSupport
* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default. * `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default.
* `config.active_record.whitelist_attributes` will create an empty whitelist of attributes available for mass-assignment security for all models in your app.
* `config.active_record.auto_explain_threshold_in_seconds` configures the threshold for automatic EXPLAINs (`nil` disables this feature). Queries exceeding the threshold get their query plan logged. Default is 0.5 in development mode. * `config.active_record.auto_explain_threshold_in_seconds` configures the threshold for automatic EXPLAINs (`nil` disables this feature). Queries exceeding the threshold get their query plan logged. Default is 0.5 in development mode.
* `config.active_record.mass_assignment_sanitizer` will determine the strictness of the mass assignment sanitization within Rails. Defaults to `:strict`. In this mode, mass assigning any non-`attr_accessible` attribute in a `create` or `update_attributes` call will raise an exception. Setting this option to `:logger` will only print to the log file when an attribute is being assigned and will not raise an exception.
The MySQL adapter adds one additional configuration option: The MySQL adapter adds one additional configuration option:
* `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default. * `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default.
...@@ -304,27 +300,21 @@ The schema dumper adds one additional configuration option: ...@@ -304,27 +300,21 @@ The schema dumper adds one additional configuration option:
* `config.action_controller.asset_path` takes a block which configures where assets can be found. Shorter version of `config.action_controller.asset_path`. * `config.action_controller.asset_path` takes a block which configures where assets can be found. Shorter version of `config.action_controller.asset_path`.
* `config.action_controller.page_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.public_path` (which is usually set to `Rails.root ` "/public"`). Changing this setting can be useful to avoid naming conflicts with files in `public/`, but doing so will likely require configuring your web server to look in the new location for cached files.
* `config.action_controller.page_cache_extension` configures the extension used for cached pages saved to `page_cache_directory`. Defaults to `.html`.
* `config.action_controller.perform_caching` configures whether the application should perform caching or not. Set to false in development mode, true in production. * `config.action_controller.perform_caching` configures whether the application should perform caching or not. Set to false in development mode, true in production.
* `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`.
* `config.action_controller.default_charset` specifies the default character set for all renders. The default is "utf-8". * `config.action_controller.default_charset` specifies the default character set for all renders. The default is "utf-8".
* `config.action_controller.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to `nil` to disable logging. * `config.action_controller.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to `nil` to disable logging.
* `config.action_controller.request_forgery_protection_token` sets the token parameter name for RequestForgery. Calling `protect_from_forgery` sets it to `:authenticity_token` by default. * `config.action_controller.request_forgery_protection_token` sets the token parameter name for RequestForgery. Calling `protect_from_forgery` sets it to `:authenticity_token` by default.
* `config.action_controller.allow_forgery_protection` enables or disables CSRF protection. By default this is false in test mode and true in all other modes. * `config.action_controller.allow_forgery_protection` enables or disables CSRF protection. By default this is `false` in test mode and `true` in all other modes.
* `config.action_controller.relative_url_root` can be used to tell Rails that you are deploying to a subdirectory. The default is `ENV['RAILS_RELATIVE_URL_ROOT']`. * `config.action_controller.relative_url_root` can be used to tell Rails that you are deploying to a subdirectory. The default is `ENV['RAILS_RELATIVE_URL_ROOT']`.
The caching code adds two additional settings: * `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`.
* `ActionController::Base.page_cache_directory` sets the directory where Rails will create cached pages for your web server. The default is `Rails.public_path` (which is usually set to `Rails.root + "/public"`).
* `ActionController::Base.page_cache_extension` sets the extension to be used when generating pages for the cache (this is ignored if the incoming request already has an extension). The default is `.html`.
### Configuring Action Dispatch ### Configuring Action Dispatch
......
...@@ -33,10 +33,10 @@ Finally, engines would not have been possible without the work of James Adam, Pi ...@@ -33,10 +33,10 @@ Finally, engines would not have been possible without the work of James Adam, Pi
Generating an engine Generating an engine
-------------------- --------------------
To generate an engine with Rails 3.1, you will need to run the plugin generator and pass it the `--full` and `--mountable` options. To generate the beginnings of the "blorgh" engine you will need to run this command in a terminal: To generate an engine with Rails 3.2, you will need to run the plugin generator and pass it options as appropriate to the need. For the "blorgh" example, you will need to create a "mountable" engine, running this command in a terminal:
```bash ```bash
$ rails plugin new blorgh --full --mountable $ rails plugin new blorgh --mountable
``` ```
The full list of options for the plugin generator may be seen by typing: The full list of options for the plugin generator may be seen by typing:
...@@ -45,9 +45,48 @@ The full list of options for the plugin generator may be seen by typing: ...@@ -45,9 +45,48 @@ The full list of options for the plugin generator may be seen by typing:
$ rails plugin --help $ rails plugin --help
``` ```
The `--full` option tells the plugin generator that you want to create an engine, creating the basic directory structure of an engine by providing things such as an `app` directory and a `config/routes.rb` file. This generator also provides a file at `lib/blorgh/engine.rb` which is identical in function to a standard Rails application's `config/application.rb` file. The `--full` option tells the generator that you want to create an engine, including a skeleton structure by providing the following:
The `--mountable` option tells the generator to mount the engine inside the dummy testing application located at `test/dummy`. It does this by placing this line into the dummy application's routes file at `test/dummy/config/routes.rb`: * An `app` directory tree
* A `config/routes.rb` file:
```ruby
Rails.application.routes.draw do
end
```
* A file at `lib/blorgh/engine.rb` which is identical in function to a standard Rails application's `config/application.rb` file:
```ruby
module Blorgh
class Engine < ::Rails::Engine
end
end
```
The `--mountable` option tells the generator that you want to create a "mountable" and namespace-isolated engine. This generator will provide the same skeleton structure as would the `--full` option, and will add:
* Asset manifest files (`application.js` and `application.css`)
* A namespaced `ApplicationController` stub
* A namespaced `ApplicationHelper` stub
* A layout view template for the engine
* Namespace isolation to `config/routes.rb`:
```ruby
Blorgh::Engine.routes.draw do
end
```
* Namespace isolation to `lib/blorgh/engine.rb`:
```ruby
module Blorgh
class Engine < ::Rails::Engine
isolate_namespace Blorgh
end
end
```
Additionally, the `--mountable` option tells the generator to mount the engine inside the dummy testing application located at `test/dummy` by adding the following to the dummy application's routes file at `test/dummy/config/routes.rb`:
```ruby ```ruby
mount Blorgh::Engine, :at => "blorgh" mount Blorgh::Engine, :at => "blorgh"
......
...@@ -77,10 +77,17 @@ TIP: The examples below use # and $ to denote superuser and regular user termina ...@@ -77,10 +77,17 @@ TIP: The examples below use # and $ to denote superuser and regular user termina
### Installing Rails ### Installing Rails
Open up a command line prompt. On a mac this is called terminal, on windows it is called command prompt. Any commands prefaced with a dollar sign `$` should be run in the command line. Verify sure you have a current version of Ruby installed:
```bash
$ ruby -v
ruby 1.9.3p194
```
To install Rails, use the `gem install` command provided by RubyGems: To install Rails, use the `gem install` command provided by RubyGems:
```bash ```bash
# gem install rails $ gem install rails
``` ```
TIP. A number of tools exist to help you quickly install Ruby and Ruby TIP. A number of tools exist to help you quickly install Ruby and Ruby
...@@ -154,11 +161,11 @@ $ rails server ...@@ -154,11 +161,11 @@ $ rails server
TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an `execjs` error. Usually Mac OS X and Windows come with a JavaScript runtime installed. Rails adds the `therubyracer` gem to Gemfile in a commented line for new apps and you can uncomment if you need it. `therubyrhino` is the recommended runtime for JRuby users and is added by default to Gemfile in apps generated under JRuby. You can investigate about all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme). TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an `execjs` error. Usually Mac OS X and Windows come with a JavaScript runtime installed. Rails adds the `therubyracer` gem to Gemfile in a commented line for new apps and you can uncomment if you need it. `therubyrhino` is the recommended runtime for JRuby users and is added by default to Gemfile in apps generated under JRuby. You can investigate about all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme).
This will fire up WEBrick, a webserver built into Ruby by default. To see your application in action, open a browser window and navigate to [http://localhost:3000](http://localhost:3000). You should see the Rails default information page: This will fire up WEBrick, a webserver built into Ruby by default. To see your application in action, open a browser window and navigate to <http://localhost:3000>. You should see the Rails default information page:
![Welcome Aboard screenshot](images/rails_welcome.png) ![Welcome Aboard screenshot](images/rails_welcome.png)
TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server. TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. To verify the server has stopped you should see your command prompt cursor again. For most unix like systems including mac this will be a dollar sign `$`. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server.
The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your application's environment. The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your application's environment.
...@@ -207,11 +214,11 @@ Open the `app/views/welcome/index.html.erb` file in your text editor and edit it ...@@ -207,11 +214,11 @@ Open the `app/views/welcome/index.html.erb` file in your text editor and edit it
### Setting the Application Home Page ### Setting the Application Home Page
Now that we have made the controller and view, we need to tell Rails when we want Hello Rails! to show up. In our case, we want it to show up when we navigate to the root URL of our site, [http://localhost:3000](http://localhost:3000). At the moment, however, the "Welcome Aboard" smoke test is occupying that spot. Now that we have made the controller and view, we need to tell Rails when we want Hello Rails! to show up. In our case, we want it to show up when we navigate to the root URL of our site, <http://localhost:3000>. At the moment, however, the "Welcome Aboard" smoke test is occupying that spot.
To fix this, delete the `index.html` file located inside the `public` directory of the application. To fix this, delete the `index.html` file located inside the `public` directory of the application.
You need to do this because Rails will serve any static file in the `public` directory that matches a route in preference to any dynamic content you generate from the controllers. The `index.html` file is special: it will be served if a request comes in at the root route, e.g. [http://localhost:3000](http://localhost:3000). If another request such as [http://localhost:3000/welcome](http://localhost:3000/welcome) happened, a static file at `public/welcome.html` would be served first, but only if it existed. You need to do this because Rails will serve any static file in the `public` directory that matches a route in preference to any dynamic content you generate from the controllers. The `index.html` file is special: it will be served if a request comes in at the root route, e.g. <http://localhost:3000>. If another request such as <http://localhost:3000/welcome> happened, a static file at `public/welcome.html` would be served first, but only if it existed.
Next, you have to tell Rails where your actual home page is located. Next, you have to tell Rails where your actual home page is located.
...@@ -235,9 +242,9 @@ This is your application's _routing file_ which holds entries in a special DSL ( ...@@ -235,9 +242,9 @@ This is your application's _routing file_ which holds entries in a special DSL (
root :to => "welcome#index" root :to => "welcome#index"
``` ```
The `root :to => "welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to [http://localhost:3000/welcome/index](http://localhost:3000/welcome/index) to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`). The `root :to => "welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to <http://localhost:3000/welcome/index> to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`).
If you navigate to [http://localhost:3000](http://localhost:3000) in your browser, you'll see the `Hello, Rails!` message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` action and is rendering the view correctly. If you navigate to <http://localhost:3000> in your browser, you'll see the `Hello, Rails!` message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` action and is rendering the view correctly.
NOTE. For more information about routing, refer to [Rails Routing from the Outside In](routing.html). NOTE. For more information about routing, refer to [Rails Routing from the Outside In](routing.html).
...@@ -256,7 +263,7 @@ It will look a little basic for now, but that's ok. We'll look at improving the ...@@ -256,7 +263,7 @@ It will look a little basic for now, but that's ok. We'll look at improving the
### Laying down the ground work ### Laying down the ground work
The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. If you attempt to navigate to that now -- by visiting [http://localhost:3000/posts/new](http://localhost:3000/posts/new) -- Rails will give you a routing error: The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. If you attempt to navigate to that now -- by visiting <http://localhost:3000/posts/new> -- Rails will give you a routing error:
![A routing error, no route matches /posts/new](images/getting_started/routing_error_no_route_matches.png) ![A routing error, no route matches /posts/new](images/getting_started/routing_error_no_route_matches.png)
...@@ -270,7 +277,7 @@ get "posts/new" ...@@ -270,7 +277,7 @@ get "posts/new"
This route is a super-simple route: it defines a new route that only responds to `GET` requests, and that the route is at `posts/new`. But how does it know where to go without the use of the `:to` option? Well, Rails uses a sensible default here: Rails will assume that you want this route to go to the new action inside the posts controller. This route is a super-simple route: it defines a new route that only responds to `GET` requests, and that the route is at `posts/new`. But how does it know where to go without the use of the `:to` option? Well, Rails uses a sensible default here: Rails will assume that you want this route to go to the new action inside the posts controller.
With the route defined, requests can now be made to `/posts/new` in the application. Navigate to [http://localhost:3000/posts/new](http://localhost:3000/posts/new) and you'll see another routing error: With the route defined, requests can now be made to `/posts/new` in the application. Navigate to <http://localhost:3000/posts/new> and you'll see another routing error:
![Another routing error, uninitialized constant PostsController](images/getting_started/routing_error_no_controller.png) ![Another routing error, uninitialized constant PostsController](images/getting_started/routing_error_no_controller.png)
...@@ -289,7 +296,7 @@ end ...@@ -289,7 +296,7 @@ end
A controller is simply a class that is defined to inherit from `ApplicationController`. It's inside this class that you'll define methods that will become the actions for this controller. These actions will perform CRUD operations on the posts within our system. A controller is simply a class that is defined to inherit from `ApplicationController`. It's inside this class that you'll define methods that will become the actions for this controller. These actions will perform CRUD operations on the posts within our system.
If you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) now, you'll get a new error: If you refresh <http://localhost:3000/posts/new> now, you'll get a new error:
![Unknown action new for PostsController!](images/getting_started/unknown_action_new_for_posts.png) ![Unknown action new for PostsController!](images/getting_started/unknown_action_new_for_posts.png)
...@@ -302,7 +309,7 @@ def new ...@@ -302,7 +309,7 @@ def new
end end
``` ```
With the `new` method defined in `PostsController`, if you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll see another error: With the `new` method defined in `PostsController`, if you refresh <http://localhost:3000/posts/new> you'll see another error:
![Template is missing for posts/new](images/getting_started/template_is_missing_posts_new.png) ![Template is missing for posts/new](images/getting_started/template_is_missing_posts_new.png)
...@@ -330,7 +337,7 @@ Go ahead now and create a new file at `app/views/posts/new.html.erb` and write t ...@@ -330,7 +337,7 @@ Go ahead now and create a new file at `app/views/posts/new.html.erb` and write t
<h1>New Post</h1> <h1>New Post</h1>
``` ```
When you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll now see that the page has a title. The route, controller, action and view are now working harmoniously! It's time to create the form for a new post. When you refresh <http://localhost:3000/posts/new> you'll now see that the page has a title. The route, controller, action and view are now working harmoniously! It's time to create the form for a new post.
### The first form ### The first form
...@@ -579,7 +586,7 @@ content: ...@@ -579,7 +586,7 @@ content:
``` ```
Finally, if you now go to Finally, if you now go to
[http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll <http://localhost:3000/posts/new> you'll
be able to create a post. Try it! be able to create a post. Try it!
![Show action for posts](images/getting_started/show_action_for_posts.png) ![Show action for posts](images/getting_started/show_action_for_posts.png)
...@@ -756,7 +763,7 @@ Notice that inside the `create` action we use `render` instead of `redirect_to` ...@@ -756,7 +763,7 @@ Notice that inside the `create` action we use `render` instead of `redirect_to`
returns `false`. The `render` method is used so that the `@post` object is passed back to the `new` template when it is rendered. This rendering is done within the same request as the form submission, whereas the `redirect_to` will tell the browser to issue another request. returns `false`. The `render` method is used so that the `@post` object is passed back to the `new` template when it is rendered. This rendering is done within the same request as the form submission, whereas the `redirect_to` will tell the browser to issue another request.
If you reload If you reload
[http://localhost:3000/posts/new](http://localhost:3000/posts/new) and <http://localhost:3000/posts/new> and
try to save a post without a title, Rails will send you back to the try to save a post without a title, Rails will send you back to the
form, but that's not very useful. You need to tell the user that form, but that's not very useful. You need to tell the user that
something went wrong. To do that, you'll modify something went wrong. To do that, you'll modify
...@@ -1037,7 +1044,7 @@ Then do the same for the `app/views/posts/edit.html.erb` view: ...@@ -1037,7 +1044,7 @@ Then do the same for the `app/views/posts/edit.html.erb` view:
<%= link_to 'Back', :action => :index %> <%= link_to 'Back', :action => :index %>
``` ```
Point your browser to [http://localhost:3000/posts/new](http://localhost:3000/posts/new) and Point your browser to <http://localhost:3000/posts/new> and
try creating a new post. Everything still works. Now try editing the try creating a new post. Everything still works. Now try editing the
post and you'll receive the following error: post and you'll receive the following error:
...@@ -1057,10 +1064,10 @@ If you run `rake routes` from the console you'll see that we already ...@@ -1057,10 +1064,10 @@ If you run `rake routes` from the console you'll see that we already
have a `posts_path` route, which was created automatically by Rails when we have a `posts_path` route, which was created automatically by Rails when we
defined the route for the index action. defined the route for the index action.
However, we don't have a `post_path` yet, which is the reason why we However, we don't have a `post_path` yet, which is the reason why we
received an error before. received an error before. With your server running you can view your routes by visiting [localhost:3000/rails/info/routes](http://localhost:3000/rails/info/routes), or you can generate them from the command line by running `rake routes`:
```bash ```bash
# rake routes $ rake routes
posts GET /posts(.:format) posts#index posts GET /posts(.:format) posts#index
posts_new GET /posts/new(.:format) posts#new posts_new GET /posts/new(.:format) posts#new
...@@ -1198,7 +1205,7 @@ If you run `rake routes`, you'll see that all the routes that we ...@@ -1198,7 +1205,7 @@ If you run `rake routes`, you'll see that all the routes that we
declared before are still available: declared before are still available:
```bash ```bash
# rake routes $ rake routes
posts GET /posts(.:format) posts#index posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new new_post GET /posts/new(.:format) posts#new
......
...@@ -94,13 +94,13 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor ...@@ -94,13 +94,13 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor
The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations. The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations.
NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](ht) NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](https://github.com/joshmh/globalize2/tree/master) may help you implement it.
The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you. The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
NOTE: The backend will lazy-load these translations when a translation is looked up for the first time. This makes it possible to just swap the backend with something else even after translations have already been announced. NOTE: The backend will lazy-load these translations when a translation is looked up for the first time. This makes it possible to just swap the backend with something else even after translations have already been announced.
The default `application.rb` files has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines. The default initializer `locale.rb` file has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines.
```ruby ```ruby
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
......
...@@ -85,7 +85,7 @@ existing users. ...@@ -85,7 +85,7 @@ existing users.
### Using the change method ### Using the change method
Rails 3.1 makes migrations smarter by providing a new `change` method. Rails 3.1 and up makes migrations smarter by providing a `change` method.
This method is preferred for writing constructive migrations (adding columns or This method is preferred for writing constructive migrations (adding columns or
tables). The migration knows how to migrate your database and reverse it when tables). The migration knows how to migrate your database and reverse it when
the migration is rolled back without the need to write a separate `down` method. the migration is rolled back without the need to write a separate `down` method.
...@@ -235,6 +235,8 @@ adding these columns will also be created. For example, running ...@@ -235,6 +235,8 @@ adding these columns will also be created. For example, running
$ rails generate model Product name:string description:text $ rails generate model Product name:string description:text
``` ```
TIP: All lines starting with a dollar sign `$` are intended to be run on the command line.
will create a migration that looks like this will create a migration that looks like this
```ruby ```ruby
...@@ -544,7 +546,7 @@ support](#active-record-and-referential-integrity). ...@@ -544,7 +546,7 @@ support](#active-record-and-referential-integrity).
If the helpers provided by Active Record aren't enough you can use the `execute` If the helpers provided by Active Record aren't enough you can use the `execute`
method to execute arbitrary SQL. method to execute arbitrary SQL.
For more details and examples of individual methods, check the API documentation. For more details and examples of individual methods, check the API documentation.
In particular the documentation for In particular the documentation for
[`ActiveRecord::ConnectionAdapters::SchemaStatements`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html) [`ActiveRecord::ConnectionAdapters::SchemaStatements`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html)
(which provides the methods available in the `up` and `down` methods), (which provides the methods available in the `up` and `down` methods),
...@@ -700,6 +702,14 @@ will run the `up` method from the 20080906120000 migration. This task will first ...@@ -700,6 +702,14 @@ will run the `up` method from the 20080906120000 migration. This task will first
check whether the migration is already performed and will do nothing if Active Record believes check whether the migration is already performed and will do nothing if Active Record believes
that it has already been run. that it has already been run.
### Running Migrations in Different Environments
By default running `rake db:migrate` will run in the `development` environment. To run migrations against another environment you can specify it using the `RAILS_ENV` environment variable while running the command. For example to run migrations against the `test` environment you could run:
```bash
$ rake db:migrate RAILS_ENV=test
```
### Changing the Output of Running Migrations ### Changing the Output of Running Migrations
By default migrations tell you exactly what they're doing and how long it took. By default migrations tell you exactly what they're doing and how long it took.
......
...@@ -162,8 +162,8 @@ You can add a new middleware to the middleware stack using any of the following ...@@ -162,8 +162,8 @@ You can add a new middleware to the middleware stack using any of the following
config.middleware.use Rack::BounceFavicon config.middleware.use Rack::BounceFavicon
# Add Lifo::Cache after ActiveRecord::QueryCache. # Add Lifo::Cache after ActiveRecord::QueryCache.
# Pass { :page_cache => false } argument to Lifo::Cache. # Pass { page_cache: false } argument to Lifo::Cache.
config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, :page_cache => false config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, page_cache: false
``` ```
#### Swapping a Middleware #### Swapping a Middleware
......
...@@ -30,14 +30,14 @@ it asks the router to match it to a controller action. If the first matching rou ...@@ -30,14 +30,14 @@ it asks the router to match it to a controller action. If the first matching rou
get "/patients/:id" => "patients#show" get "/patients/:id" => "patients#show"
``` ```
the request is dispatched to the `patients` controller's `show` action with `{ :id => "17" }` in `params`. the request is dispatched to the `patients` controller's `show` action with `{ id: "17" }` in `params`.
### Generating Paths and URLs from Code ### Generating Paths and URLs from Code
You can also generate paths and URLs. If the route above is modified to be You can also generate paths and URLs. If the route above is modified to be
```ruby ```ruby
get "/patients/:id" => "patients#show", :as => "patient" get "/patients/:id" => "patients#show", as: "patient"
``` ```
If your application contains this code: If your application contains this code:
...@@ -73,7 +73,7 @@ it asks the router to map it to a controller action. If the first matching route ...@@ -73,7 +73,7 @@ it asks the router to map it to a controller action. If the first matching route
resources :photos resources :photos
``` ```
Rails would dispatch that request to the `destroy` method on the `photos` controller with `{ :id => "17" }` in `params`. Rails would dispatch that request to the `destroy` method on the `photos` controller with `{ id: "17" }` in `params`.
### CRUD, Verbs, and Actions ### CRUD, Verbs, and Actions
...@@ -186,7 +186,7 @@ This will create a number of routes for each of the `posts` and `comments` contr ...@@ -186,7 +186,7 @@ This will create a number of routes for each of the `posts` and `comments` contr
If you want to route `/posts` (without the prefix `/admin`) to `Admin::PostsController`, you could use If you want to route `/posts` (without the prefix `/admin`) to `Admin::PostsController`, you could use
```ruby ```ruby
scope :module => "admin" do scope module: "admin" do
resources :posts, :comments resources :posts, :comments
end end
``` ```
...@@ -194,7 +194,7 @@ end ...@@ -194,7 +194,7 @@ end
or, for a single case or, for a single case
```ruby ```ruby
resources :posts, :module => "admin" resources :posts, module: "admin"
``` ```
If you want to route `/admin/posts` to `PostsController` (without the `Admin::` module prefix), you could use If you want to route `/admin/posts` to `PostsController` (without the `Admin::` module prefix), you could use
...@@ -208,7 +208,7 @@ end ...@@ -208,7 +208,7 @@ end
or, for a single case or, for a single case
```ruby ```ruby
resources :posts, :path => "/admin/posts" resources :posts, path: "/admin/posts"
``` ```
In each of these cases, the named routes remain the same as if you did not use `scope`. In the last case, the following paths map to `PostsController`: In each of these cases, the named routes remain the same as if you did not use `scope`. In the last case, the following paths map to `PostsController`:
...@@ -375,7 +375,7 @@ Within the block of member routes, each route name specifies the HTTP verb that ...@@ -375,7 +375,7 @@ Within the block of member routes, each route name specifies the HTTP verb that
```ruby ```ruby
resources :photos do resources :photos do
get 'preview', :on => :member get 'preview', on: :member
end end
``` ```
...@@ -397,7 +397,7 @@ Just as with member routes, you can pass `:on` to a route: ...@@ -397,7 +397,7 @@ Just as with member routes, you can pass `:on` to a route:
```ruby ```ruby
resources :photos do resources :photos do
get 'search', :on => :collection get 'search', on: :collection
end end
``` ```
...@@ -407,7 +407,7 @@ To add an alternate new action using the `:on` shortcut: ...@@ -407,7 +407,7 @@ To add an alternate new action using the `:on` shortcut:
```ruby ```ruby
resources :comments do resources :comments do
get 'preview', :on => :new get 'preview', on: :new
end end
``` ```
...@@ -449,10 +449,10 @@ An incoming path of `/photos/show/1/2` will be dispatched to the `show` action o ...@@ -449,10 +449,10 @@ An incoming path of `/photos/show/1/2` will be dispatched to the `show` action o
NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g: NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:
```ruby ```ruby
get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/ get ':controller(/:action(/:id))', controller: /admin\/[^\/]+/
``` ```
TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `:id => /[^\/]+/` allows anything except a slash. TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `id: /[^\/]+/` allows anything except a slash.
### Static Segments ### Static Segments
...@@ -462,7 +462,7 @@ You can specify static segments when creating a route: ...@@ -462,7 +462,7 @@ You can specify static segments when creating a route:
get ':controller/:action/:id/with_user/:user_id' get ':controller/:action/:id/with_user/:user_id'
``` ```
This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }`. This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ controller: "photos", action: "show", id: "1", user_id: "2" }`.
### The Query String ### The Query String
...@@ -472,7 +472,7 @@ The `params` will also include any parameters from the query string. For example ...@@ -472,7 +472,7 @@ The `params` will also include any parameters from the query string. For example
get ':controller/:action/:id' get ':controller/:action/:id'
``` ```
An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }`. An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: "photos", action: "show", id: "1", user_id: "2" }`.
### Defining Defaults ### Defining Defaults
...@@ -487,7 +487,7 @@ With this route, Rails will match an incoming path of `/photos/12` to the `show` ...@@ -487,7 +487,7 @@ With this route, Rails will match an incoming path of `/photos/12` to the `show`
You can also define other defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example: You can also define other defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example:
```ruby ```ruby
get 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' } get 'photos/:id' => 'photos#show', defaults: { format: 'jpg' }
``` ```
Rails would match `photos/12` to the `show` action of `PhotosController`, and set `params[:format]` to `"jpg"`. Rails would match `photos/12` to the `show` action of `PhotosController`, and set `params[:format]` to `"jpg"`.
...@@ -497,7 +497,7 @@ Rails would match `photos/12` to the `show` action of `PhotosController`, and se ...@@ -497,7 +497,7 @@ Rails would match `photos/12` to the `show` action of `PhotosController`, and se
You can specify a name for any route using the `:as` option. You can specify a name for any route using the `:as` option.
```ruby ```ruby
get 'exit' => 'sessions#destroy', :as => :logout get 'exit' => 'sessions#destroy', as: :logout
``` ```
This will create `logout_path` and `logout_url` as named helpers in your application. Calling `logout_path` will return `/exit` This will create `logout_path` and `logout_url` as named helpers in your application. Calling `logout_path` will return `/exit`
...@@ -505,7 +505,7 @@ This will create `logout_path` and `logout_url` as named helpers in your applica ...@@ -505,7 +505,7 @@ This will create `logout_path` and `logout_url` as named helpers in your applica
You can also use this to override routing methods defined by resources, like this: You can also use this to override routing methods defined by resources, like this:
```ruby ```ruby
get ':username', :to => "users#show", :as => :user get ':username', to: "users#show", as: :user
``` ```
This will define a `user_path` method that will be available in controllers, helpers and views that will go to a route such as `/bob`. Inside the `show` action of `UsersController`, `params[:username]` will contain the username for the user. Change `:username` in the route definition if you do not want your parameter name to be `:username`. This will define a `user_path` method that will be available in controllers, helpers and views that will go to a route such as `/bob`. Inside the `show` action of `UsersController`, `params[:username]` will contain the username for the user. Change `:username` in the route definition if you do not want your parameter name to be `:username`.
...@@ -515,13 +515,13 @@ This will define a `user_path` method that will be available in controllers, hel ...@@ -515,13 +515,13 @@ This will define a `user_path` method that will be available in controllers, hel
In general, you should use the `get`, `post`, `put` and `delete` methods to constrain a route to a particular verb. You can use the `match` method with the `:via` option to match multiple verbs at once: In general, you should use the `get`, `post`, `put` and `delete` methods to constrain a route to a particular verb. You can use the `match` method with the `:via` option to match multiple verbs at once:
```ruby ```ruby
match 'photos' => 'photos#show', :via => [:get, :post] match 'photos' => 'photos#show', via: [:get, :post]
``` ```
You can match all verbs to a particular route using `:via => :all`: You can match all verbs to a particular route using `via: :all`:
```ruby ```ruby
match 'photos' => 'photos#show', :via => :all match 'photos' => 'photos#show', via: :all
``` ```
You should avoid routing all verbs to an action unless you have a good reason to, as routing both `GET` requests and `POST` requests to a single action has security implications. You should avoid routing all verbs to an action unless you have a good reason to, as routing both `GET` requests and `POST` requests to a single action has security implications.
...@@ -531,19 +531,19 @@ You should avoid routing all verbs to an action unless you have a good reason to ...@@ -531,19 +531,19 @@ You should avoid routing all verbs to an action unless you have a good reason to
You can use the `:constraints` option to enforce a format for a dynamic segment: You can use the `:constraints` option to enforce a format for a dynamic segment:
```ruby ```ruby
get 'photos/:id' => 'photos#show', :constraints => { :id => /[A-Z]\d{5}/ } get 'photos/:id' => 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
``` ```
This route would match paths such as `/photos/A12345`. You can more succinctly express the same route this way: This route would match paths such as `/photos/A12345`. You can more succinctly express the same route this way:
```ruby ```ruby
get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ get 'photos/:id' => 'photos#show', id: /[A-Z]\d{5}/
``` ```
`:constraints` takes regular expressions with the restriction that regexp anchors can't be used. For example, the following route will not work: `:constraints` takes regular expressions with the restriction that regexp anchors can't be used. For example, the following route will not work:
```ruby ```ruby
get '/:id' => 'posts#show', :constraints => {:id => /^\d/} get '/:id' => 'posts#show', constraints: {id: /^\d/}
``` ```
However, note that you don't need to use anchors because all routes are anchored at the start. However, note that you don't need to use anchors because all routes are anchored at the start.
...@@ -551,7 +551,7 @@ However, note that you don't need to use anchors because all routes are anchored ...@@ -551,7 +551,7 @@ However, note that you don't need to use anchors because all routes are anchored
For example, the following routes would allow for `posts` with `to_param` values like `1-hello-world` that always begin with a number and `users` with `to_param` values like `david` that never begin with a number to share the root namespace: For example, the following routes would allow for `posts` with `to_param` values like `1-hello-world` that always begin with a number and `users` with `to_param` values like `david` that never begin with a number to share the root namespace:
```ruby ```ruby
get '/:id' => 'posts#show', :constraints => { :id => /\d.+/ } get '/:id' => 'posts#show', constraints: { id: /\d.+/ }
get '/:username' => 'users#show' get '/:username' => 'users#show'
``` ```
...@@ -562,14 +562,14 @@ You can also constrain a route based on any method on the <a href="action_contro ...@@ -562,14 +562,14 @@ You can also constrain a route based on any method on the <a href="action_contro
You specify a request-based constraint the same way that you specify a segment constraint: You specify a request-based constraint the same way that you specify a segment constraint:
```ruby ```ruby
get "photos", :constraints => {:subdomain => "admin"} get "photos", constraints: {subdomain: "admin"}
``` ```
You can also specify constraints in a block form: You can also specify constraints in a block form:
```ruby ```ruby
namespace :admin do namespace :admin do
constraints :subdomain => "admin" do constraints subdomain: "admin" do
resources :photos resources :photos
end end
end end
...@@ -592,7 +592,7 @@ end ...@@ -592,7 +592,7 @@ end
TwitterClone::Application.routes.draw do TwitterClone::Application.routes.draw do
get "*path" => "blacklist#index", get "*path" => "blacklist#index",
:constraints => BlacklistConstraint.new constraints: BlacklistConstraint.new
end end
``` ```
...@@ -601,7 +601,7 @@ You can also specify constraints as a lambda: ...@@ -601,7 +601,7 @@ You can also specify constraints as a lambda:
```ruby ```ruby
TwitterClone::Application.routes.draw do TwitterClone::Application.routes.draw do
get "*path" => "blacklist#index", get "*path" => "blacklist#index",
:constraints => lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) } constraints: lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) }
end end
``` ```
...@@ -639,16 +639,16 @@ NOTE: Starting from Rails 3.1, wildcard routes will always match the optional fo ...@@ -639,16 +639,16 @@ NOTE: Starting from Rails 3.1, wildcard routes will always match the optional fo
get '*pages' => 'pages#show' get '*pages' => 'pages#show'
``` ```
NOTE: By requesting `"/foo/bar.json"`, your `params[:pages]` will be equals to `"foo/bar"` with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `:format => false` like this: NOTE: By requesting `"/foo/bar.json"`, your `params[:pages]` will be equals to `"foo/bar"` with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `format: false` like this:
```ruby ```ruby
get '*pages' => 'pages#show', :format => false get '*pages' => 'pages#show', format: false
``` ```
NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply `:format => true` like this: NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply `format: true` like this:
```ruby ```ruby
get '*pages' => 'pages#show', :format => true get '*pages' => 'pages#show', format: true
``` ```
### Redirection ### Redirection
...@@ -681,10 +681,10 @@ In all of these cases, if you don't provide the leading host (`http://www.exampl ...@@ -681,10 +681,10 @@ In all of these cases, if you don't provide the leading host (`http://www.exampl
Instead of a String, like `"posts#index"`, which corresponds to the `index` action in the `PostsController`, you can specify any <a href="rails_on_rack.html">Rack application</a> as the endpoint for a matcher. Instead of a String, like `"posts#index"`, which corresponds to the `index` action in the `PostsController`, you can specify any <a href="rails_on_rack.html">Rack application</a> as the endpoint for a matcher.
```ruby ```ruby
match "/application.js" => Sprockets, :via => :all match "/application.js" => Sprockets, via: :all
``` ```
As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `:via => :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate. As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate.
NOTE: For the curious, `"posts#index"` actually expands out to `PostsController.action(:index)`, which returns a valid Rack application. NOTE: For the curious, `"posts#index"` actually expands out to `PostsController.action(:index)`, which returns a valid Rack application.
...@@ -693,7 +693,7 @@ NOTE: For the curious, `"posts#index"` actually expands out to `PostsController. ...@@ -693,7 +693,7 @@ NOTE: For the curious, `"posts#index"` actually expands out to `PostsController.
You can specify what Rails should route `"/"` to with the `root` method: You can specify what Rails should route `"/"` to with the `root` method:
```ruby ```ruby
root :to => 'pages#main' root to: 'pages#main'
root 'pages#main' # shortcut for the above root 'pages#main' # shortcut for the above
``` ```
...@@ -719,7 +719,7 @@ While the default routes and helpers generated by `resources :posts` will usuall ...@@ -719,7 +719,7 @@ While the default routes and helpers generated by `resources :posts` will usuall
The `:controller` option lets you explicitly specify a controller to use for the resource. For example: The `:controller` option lets you explicitly specify a controller to use for the resource. For example:
```ruby ```ruby
resources :photos, :controller => "images" resources :photos, controller: "images"
``` ```
will recognize incoming paths beginning with `/photos` but route to the `Images` controller: will recognize incoming paths beginning with `/photos` but route to the `Images` controller:
...@@ -741,7 +741,7 @@ NOTE: Use `photos_path`, `new_photo_path`, etc. to generate paths for this resou ...@@ -741,7 +741,7 @@ NOTE: Use `photos_path`, `new_photo_path`, etc. to generate paths for this resou
You can use the `:constraints` option to specify a required format on the implicit `id`. For example: You can use the `:constraints` option to specify a required format on the implicit `id`. For example:
```ruby ```ruby
resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/} resources :photos, constraints: {id: /[A-Z][A-Z][0-9]+/}
``` ```
This declaration constrains the `:id` parameter to match the supplied regular expression. So, in this case, the router would no longer match `/photos/1` to this route. Instead, `/photos/RR27` would match. This declaration constrains the `:id` parameter to match the supplied regular expression. So, in this case, the router would no longer match `/photos/1` to this route. Instead, `/photos/RR27` would match.
...@@ -749,7 +749,7 @@ This declaration constrains the `:id` parameter to match the supplied regular ex ...@@ -749,7 +749,7 @@ This declaration constrains the `:id` parameter to match the supplied regular ex
You can specify a single constraint to apply to a number of routes by using the block form: You can specify a single constraint to apply to a number of routes by using the block form:
```ruby ```ruby
constraints(:id => /[A-Z][A-Z][0-9]+/) do constraints(id: /[A-Z][A-Z][0-9]+/) do
resources :photos resources :photos
resources :accounts resources :accounts
end end
...@@ -757,14 +757,14 @@ end ...@@ -757,14 +757,14 @@ end
NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context. NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context.
TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `:id => /[^\/]+/` allows anything except a slash. TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `id: /[^\/]+/` allows anything except a slash.
### Overriding the Named Helpers ### Overriding the Named Helpers
The `:as` option lets you override the normal naming for the named route helpers. For example: The `:as` option lets you override the normal naming for the named route helpers. For example:
```ruby ```ruby
resources :photos, :as => "images" resources :photos, as: "images"
``` ```
will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers. will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers.
...@@ -784,7 +784,7 @@ will recognize incoming paths beginning with `/photos` and route the requests to ...@@ -784,7 +784,7 @@ will recognize incoming paths beginning with `/photos` and route the requests to
The `:path_names` option lets you override the automatically-generated "new" and "edit" segments in paths: The `:path_names` option lets you override the automatically-generated "new" and "edit" segments in paths:
```ruby ```ruby
resources :photos, :path_names => { :new => 'make', :edit => 'change' } resources :photos, path_names: { new: 'make', edit: 'change' }
``` ```
This would cause the routing to recognize paths such as This would cause the routing to recognize paths such as
...@@ -799,7 +799,7 @@ NOTE: The actual action names aren't changed by this option. The two paths shown ...@@ -799,7 +799,7 @@ NOTE: The actual action names aren't changed by this option. The two paths shown
TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope. TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope.
```ruby ```ruby
scope :path_names => { :new => "make" } do scope path_names: { new: "make" } do
# rest of your routes # rest of your routes
end end
``` ```
...@@ -810,7 +810,7 @@ You can use the `:as` option to prefix the named route helpers that Rails genera ...@@ -810,7 +810,7 @@ You can use the `:as` option to prefix the named route helpers that Rails genera
```ruby ```ruby
scope "admin" do scope "admin" do
resources :photos, :as => "admin_photos" resources :photos, as: "admin_photos"
end end
resources :photos resources :photos
...@@ -821,7 +821,7 @@ This will provide route helpers such as `admin_photos_path`, `new_admin_photo_pa ...@@ -821,7 +821,7 @@ This will provide route helpers such as `admin_photos_path`, `new_admin_photo_pa
To prefix a group of route helpers, use `:as` with `scope`: To prefix a group of route helpers, use `:as` with `scope`:
```ruby ```ruby
scope "admin", :as => "admin" do scope "admin", as: "admin" do
resources :photos, :accounts resources :photos, :accounts
end end
...@@ -847,7 +847,7 @@ This will provide you with URLs such as `/bob/posts/1` and will allow you to ref ...@@ -847,7 +847,7 @@ This will provide you with URLs such as `/bob/posts/1` and will allow you to ref
By default, Rails creates routes for the seven default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the `:only` and `:except` options to fine-tune this behavior. The `:only` option tells Rails to create only the specified routes: By default, Rails creates routes for the seven default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the `:only` and `:except` options to fine-tune this behavior. The `:only` option tells Rails to create only the specified routes:
```ruby ```ruby
resources :photos, :only => [:index, :show] resources :photos, only: [:index, :show]
``` ```
Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photos` (which would ordinarily be routed to the `create` action) will fail. Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photos` (which would ordinarily be routed to the `create` action) will fail.
...@@ -855,7 +855,7 @@ Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photo ...@@ -855,7 +855,7 @@ Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photo
The `:except` option specifies a route or list of routes that Rails should _not_ create: The `:except` option specifies a route or list of routes that Rails should _not_ create:
```ruby ```ruby
resources :photos, :except => :destroy resources :photos, except: :destroy
``` ```
In this case, Rails will create all of the normal routes except the route for `destroy` (a `DELETE` request to `/photos/:id`). In this case, Rails will create all of the normal routes except the route for `destroy` (a `DELETE` request to `/photos/:id`).
...@@ -867,8 +867,8 @@ TIP: If your application has many RESTful routes, using `:only` and `:except` to ...@@ -867,8 +867,8 @@ TIP: If your application has many RESTful routes, using `:only` and `:except` to
Using `scope`, we can alter path names generated by resources: Using `scope`, we can alter path names generated by resources:
```ruby ```ruby
scope(:path_names => { :new => "neu", :edit => "bearbeiten" }) do scope(path_names: { new: "neu", edit: "bearbeiten" }) do
resources :categories, :path => "kategorien" resources :categories, path: "kategorien"
end end
``` ```
...@@ -900,7 +900,7 @@ The `:as` option overrides the automatically-generated name for the resource in ...@@ -900,7 +900,7 @@ The `:as` option overrides the automatically-generated name for the resource in
```ruby ```ruby
resources :magazines do resources :magazines do
resources :ads, :as => 'periodical_ads' resources :ads, as: 'periodical_ads'
end end
``` ```
...@@ -952,8 +952,8 @@ Routes should be included in your testing strategy (just like the rest of your a ...@@ -952,8 +952,8 @@ Routes should be included in your testing strategy (just like the rest of your a
`assert_generates` asserts that a particular set of options generate a particular path and can be used with default routes or custom routes. `assert_generates` asserts that a particular set of options generate a particular path and can be used with default routes or custom routes.
```ruby ```ruby
assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" } assert_generates "/photos/1", { controller: "photos", action: "show", id: "1" }
assert_generates "/about", :controller => "pages", :action => "about" assert_generates "/about", controller: "pages", action: "about"
``` ```
#### The `assert_recognizes` Assertion #### The `assert_recognizes` Assertion
...@@ -961,13 +961,13 @@ assert_generates "/about", :controller => "pages", :action => "about" ...@@ -961,13 +961,13 @@ assert_generates "/about", :controller => "pages", :action => "about"
`assert_recognizes` is the inverse of `assert_generates`. It asserts that a given path is recognized and routes it to a particular spot in your application. `assert_recognizes` is the inverse of `assert_generates`. It asserts that a given path is recognized and routes it to a particular spot in your application.
```ruby ```ruby
assert_recognizes({ :controller => "photos", :action => "show", :id => "1" }, "/photos/1") assert_recognizes({ controller: "photos", action: "show", id: "1" }, "/photos/1")
``` ```
You can supply a `:method` argument to specify the HTTP verb: You can supply a `:method` argument to specify the HTTP verb:
```ruby ```ruby
assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }) assert_recognizes({ controller: "photos", action: "create" }, { path: "photos", method: :post })
``` ```
#### The `assert_routing` Assertion #### The `assert_routing` Assertion
...@@ -975,5 +975,5 @@ assert_recognizes({ :controller => "photos", :action => "create" }, { :path => " ...@@ -975,5 +975,5 @@ assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "
The `assert_routing` assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of `assert_generates` and `assert_recognizes`. The `assert_routing` assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of `assert_generates` and `assert_recognizes`.
```ruby ```ruby
assert_routing({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }) assert_routing({ path: "photos", method: :post }, { controller: "photos", action: "create" })
``` ```
...@@ -96,8 +96,8 @@ That means the security of this storage depends on this secret (and on the diges ...@@ -96,8 +96,8 @@ That means the security of this storage depends on this secret (and on the diges
```ruby ```ruby
config.action_dispatch.session = { config.action_dispatch.session = {
:key => '_app_session', key: '_app_session',
:secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...' secret: '0x0dkfj3927dkc7djdh36rkckdfzsg...'
} }
``` ```
...@@ -233,7 +233,7 @@ Or the attacker places the code into the onmouseover event handler of an image: ...@@ -233,7 +233,7 @@ Or the attacker places the code into the onmouseover event handler of an image:
There are many other possibilities, including Ajax to attack the victim in the background.
The _solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller: There are many other possibilities, including Ajax to attack the victim in the background.
The _solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller:
```ruby ```ruby
protect_from_forgery :secret => "123456789012345678901234567890..." protect_from_forgery secret: "123456789012345678901234567890..."
``` ```
This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. **Note:** In Rails versions prior to 3.0.4, this raised an `ActionController::InvalidAuthenticityToken` error. This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. **Note:** In Rails versions prior to 3.0.4, this raised an `ActionController::InvalidAuthenticityToken` error.
...@@ -264,7 +264,7 @@ Whenever the user is allowed to pass (parts of) the URL for redirection, it is p ...@@ -264,7 +264,7 @@ Whenever the user is allowed to pass (parts of) the URL for redirection, it is p
```ruby ```ruby
def legacy def legacy
redirect_to(params.update(:action=>'main')) redirect_to(params.update(action:'main'))
end end
``` ```
...@@ -334,7 +334,7 @@ basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files')) ...@@ -334,7 +334,7 @@ basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files'))
filename = File.expand_path(File.join(basename, @file.public_filename)) filename = File.expand_path(File.join(basename, @file.public_filename))
raise if basename != raise if basename !=
File.expand_path(File.join(File.dirname(filename), '../../../')) File.expand_path(File.join(File.dirname(filename), '../../../'))
send_file filename, :disposition => 'inline' send_file filename, disposition: 'inline'
``` ```
Another (additional) approach is to store the file names in the database and name the files on the disk after the ids in the database. This is also a good approach to avoid possible code in an uploaded file to be executed. The attachment_fu plugin does this in a similar way. Another (additional) approach is to store the file names in the database and name the files on the disk after the ids in the database. This is also a good approach to avoid possible code in an uploaded file to be executed. The attachment_fu plugin does this in a similar way.
...@@ -383,7 +383,7 @@ any model's attributes by manipulating the hash passed to a model's `new()` meth ...@@ -383,7 +383,7 @@ any model's attributes by manipulating the hash passed to a model's `new()` meth
```ruby ```ruby
def signup def signup
params[:user] # => {:name=>"ow3ned", :admin=>true} params[:user] # => {name:"ow3ned", admin:true}
@user = User.new(params[:user]) @user = User.new(params[:user])
end end
``` ```
...@@ -402,7 +402,7 @@ http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1 ...@@ -402,7 +402,7 @@ http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1
This will set the following parameters in the controller: This will set the following parameters in the controller:
```ruby ```ruby
params[:user] # => {:name=>"ow3ned", :admin=>true} params[:user] # => {name:"ow3ned", admin:true}
``` ```
So if you create a new user using mass-assignment, it may be too easy to become So if you create a new user using mass-assignment, it may be too easy to become
...@@ -459,9 +459,9 @@ should be allowed for mass updating using the slice pattern. For example: ...@@ -459,9 +459,9 @@ should be allowed for mass updating using the slice pattern. For example:
```ruby ```ruby
def signup def signup
params[:user] params[:user]
# => {:name=>"ow3ned", :admin=>true} # => {name:"ow3ned", admin:true}
permitted_params = params.require(:user).permit(:name) permitted_params = params.require(:user).permit(:name)
# => {:name=>"ow3ned"} # => {name:"ow3ned"}
@user = User.new(permitted_params) @user = User.new(permitted_params)
end end
...@@ -499,10 +499,11 @@ attributes. ...@@ -499,10 +499,11 @@ attributes.
```ruby ```ruby
def user_params def user_params
filters = [:name] if current_user.admin?
filters << :admin if current_user.try(:admin?) params.require(:user).permit(:name, :admin)
else
params.require(:user).permit(*filters) params.require(:user).permit(:name)
end
end end
``` ```
...@@ -647,7 +648,7 @@ Since this is a frequent mistake, the format validator (validates_format_of) now ...@@ -647,7 +648,7 @@ Since this is a frequent mistake, the format validator (validates_format_of) now
```ruby ```ruby
# content should include a line "Meanwhile" anywhere in the string # content should include a line "Meanwhile" anywhere in the string
validates :content, :format => { :with => /^Meanwhile$/, :multiline => true } validates :content, format: { with: /^Meanwhile$/, multiline: true }
``` ```
Note that this only protects you against the most common mistake when using the format validator - you always need to keep in mind that ^ and $ match the **line** beginning and line end in Ruby, and not the beginning and end of a string. Note that this only protects you against the most common mistake when using the format validator - you always need to keep in mind that ^ and $ match the **line** beginning and line end in Ruby, and not the beginning and end of a string.
...@@ -685,7 +686,7 @@ NOTE: _When sanitizing, protecting or verifying something, whitelists over black ...@@ -685,7 +686,7 @@ NOTE: _When sanitizing, protecting or verifying something, whitelists over black
A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_: A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_:
* Use before_filter :only => [...] instead of :except => [...]. This way you don't forget to turn it off for newly added actions. * Use before_filter only: [...] instead of except: [...]. This way you don't forget to turn it off for newly added actions.
* Use attr_accessible instead of attr_protected. See the mass-assignment section for details * Use attr_accessible instead of attr_protected. See the mass-assignment section for details
* Allow &lt;strong&gt; instead of removing &lt;script&gt; against Cross-Site Scripting (XSS). See below for details. * Allow &lt;strong&gt; instead of removing &lt;script&gt; against Cross-Site Scripting (XSS). See below for details.
* Don't try to correct user input by blacklists: * Don't try to correct user input by blacklists:
...@@ -768,7 +769,7 @@ Model.where("login = ? AND password = ?", entered_user_name, entered_password).f ...@@ -768,7 +769,7 @@ Model.where("login = ? AND password = ?", entered_user_name, entered_password).f
As you can see, the first part of the array is an SQL fragment with question marks. The sanitized versions of the variables in the second part of the array replace the question marks. Or you can pass a hash for the same result: As you can see, the first part of the array is an SQL fragment with question marks. The sanitized versions of the variables in the second part of the array replace the question marks. Or you can pass a hash for the same result:
```ruby ```ruby
Model.where(:login => entered_user_name, :password => entered_password).first Model.where(login: entered_user_name, password: entered_password).first
``` ```
The array or hash form is only available in model instances. You can try `sanitize_sql()` elsewhere. _Make it a habit to think about the security consequences when using an external string in SQL_. The array or hash form is only available in model instances. You can try `sanitize_sql()` elsewhere. _Make it a habit to think about the security consequences when using an external string in SQL_.
...@@ -863,7 +864,7 @@ This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an ...@@ -863,7 +864,7 @@ This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an
```ruby ```ruby
tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p)
s = sanitize(user_input, :tags => tags, :attributes => %w(href title)) s = sanitize(user_input, tags: tags, attributes: %w(href title))
``` ```
This allows only the given tags and does a good job, even against all kinds of tricks and malformed tags. This allows only the given tags and does a good job, even against all kinds of tricks and malformed tags.
......
...@@ -255,7 +255,7 @@ ActiveSupport.on_load(:active_record) do ...@@ -255,7 +255,7 @@ ActiveSupport.on_load(:active_record) do
end end
``` ```
h4(#config_session3_1). config/initializers/session_store.rb ### config/initializers/session_store.rb
You need to change your session key to something new, or remove all sessions: You need to change your session key to something new, or remove all sessions:
...@@ -266,4 +266,6 @@ AppName::Application.config.session_store :cookie_store, :key => 'SOMETHINGNEW' ...@@ -266,4 +266,6 @@ AppName::Application.config.session_store :cookie_store, :key => 'SOMETHINGNEW'
or or
<tt>$ rake db:sessions:clear</tt> ```bash
$ rake db:sessions:clear
```
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
module Rails module Rails
module Generators module Generators
class AppGenerator class AppGenerator # :nodoc:
# We want to exit on failure to be kind to other libraries # We want to exit on failure to be kind to other libraries
# This is only when accessing via CLI # This is only when accessing via CLI
def self.exit_on_failure? def self.exit_on_failure?
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
module Rails module Rails
module Generators module Generators
class AppBase < Base class AppBase < Base # :nodoc:
DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver ) DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver )
JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc )
DATABASES.concat(JDBC_DATABASES) DATABASES.concat(JDBC_DATABASES)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
module Rails module Rails
module Generators module Generators
class Error < Thor::Error class Error < Thor::Error # :nodoc:
end end
class Base < Thor::Group class Base < Thor::Group
......
require "rails/generators/named_base" require "rails/generators/named_base"
module Css module Css # :nodoc:
module Generators module Generators # :nodoc:
class AssetsGenerator < Rails::Generators::NamedBase class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
source_root File.expand_path("../templates", __FILE__) source_root File.expand_path("../templates", __FILE__)
def copy_stylesheet def copy_stylesheet
......
require "rails/generators/named_base" require "rails/generators/named_base"
module Css module Css # :nodoc:
module Generators module Generators # :nodoc:
class ScaffoldGenerator < Rails::Generators::NamedBase class ScaffoldGenerator < Rails::Generators::NamedBase # :nodoc:
# In order to allow the Sass generators to pick up the default Rails CSS and # In order to allow the Sass generators to pick up the default Rails CSS and
# transform it, we leave it in a standard location for the CSS stylesheet # transform it, we leave it in a standard location for the CSS stylesheet
# generators to handle. For the simple, default case, just copy it over. # generators to handle. For the simple, default case, just copy it over.
......
require 'rails/generators/named_base' require 'rails/generators/named_base'
module Erb module Erb # :nodoc:
module Generators module Generators # :nodoc:
class Base < Rails::Generators::NamedBase #:nodoc: class Base < Rails::Generators::NamedBase #:nodoc:
protected protected
......
require 'rails/generators/erb' require 'rails/generators/erb'
module Erb module Erb # :nodoc:
module Generators module Generators # :nodoc:
class ControllerGenerator < Base class ControllerGenerator < Base # :nodoc:
argument :actions, :type => :array, :default => [], :banner => "action action" argument :actions, :type => :array, :default => [], :banner => "action action"
def copy_view_files def copy_view_files
......
require 'rails/generators/erb/controller/controller_generator' require 'rails/generators/erb/controller/controller_generator'
module Erb module Erb # :nodoc:
module Generators module Generators # :nodoc:
class MailerGenerator < ControllerGenerator class MailerGenerator < ControllerGenerator # :nodoc:
protected protected
def format def format
......
require 'rails/generators/erb' require 'rails/generators/erb'
require 'rails/generators/resource_helpers' require 'rails/generators/resource_helpers'
module Erb module Erb # :nodoc:
module Generators module Generators # :nodoc:
class ScaffoldGenerator < Base class ScaffoldGenerator < Base # :nodoc:
include Rails::Generators::ResourceHelpers include Rails::Generators::ResourceHelpers
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Rails module Rails
module Generators module Generators
class GeneratedAttribute class GeneratedAttribute # :nodoc:
INDEX_OPTIONS = %w(index uniq) INDEX_OPTIONS = %w(index uniq)
UNIQ_INDEX_OPTIONS = %w(uniq) UNIQ_INDEX_OPTIONS = %w(uniq)
......
require "rails/generators/named_base" require "rails/generators/named_base"
module Js module Js # :nodoc:
module Generators module Generators # :nodoc:
class AssetsGenerator < Rails::Generators::NamedBase class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
source_root File.expand_path("../templates", __FILE__) source_root File.expand_path("../templates", __FILE__)
def copy_javascript def copy_javascript
......
require 'rails/generators/app_base' require 'rails/generators/app_base'
module Rails module Rails
module ActionMethods module ActionMethods # :nodoc:
attr_reader :options attr_reader :options
def initialize(generator) def initialize(generator)
...@@ -148,7 +148,7 @@ module Generators ...@@ -148,7 +148,7 @@ module Generators
RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test] RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test]
class AppGenerator < AppBase class AppGenerator < AppBase # :nodoc:
add_shared_options_for "application" add_shared_options_for "application"
# Add bin/rails options # Add bin/rails options
......
...@@ -60,7 +60,8 @@ ...@@ -60,7 +60,8 @@
# config.assets.precompile += %w( search.js ) # config.assets.precompile += %w( search.js )
<%- end -%> <%- end -%>
# Disable delivery errors, bad email addresses will be ignored. # Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false # config.action_mailer.raise_delivery_errors = false
# Enable threaded mode. # Enable threaded mode.
......
module Rails module Rails
module Generators module Generators
class AssetsGenerator < NamedBase class AssetsGenerator < NamedBase # :nodoc:
class_option :javascripts, :type => :boolean, :desc => "Generate JavaScripts" class_option :javascripts, :type => :boolean, :desc => "Generate JavaScripts"
class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets" class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
......
module Rails module Rails
module Generators module Generators
class ControllerGenerator < NamedBase class ControllerGenerator < NamedBase # :nodoc:
argument :actions, :type => :array, :default => [], :banner => "action action" argument :actions, :type => :array, :default => [], :banner => "action action"
check_class_collision :suffix => "Controller" check_class_collision :suffix => "Controller"
......
module Rails module Rails
module Generators module Generators
class GeneratorGenerator < NamedBase class GeneratorGenerator < NamedBase # :nodoc:
check_class_collision :suffix => "Generator" check_class_collision :suffix => "Generator"
class_option :namespace, :type => :boolean, :default => true, class_option :namespace, :type => :boolean, :default => true,
......
module Rails module Rails
module Generators module Generators
class HelperGenerator < NamedBase class HelperGenerator < NamedBase # :nodoc:
check_class_collision :suffix => "Helper" check_class_collision :suffix => "Helper"
def create_helper_files def create_helper_files
......
module Rails module Rails
module Generators module Generators
class IntegrationTestGenerator < NamedBase class IntegrationTestGenerator < NamedBase # :nodoc:
hook_for :integration_tool, :as => :integration hook_for :integration_tool, :as => :integration
end end
end end
......
module Rails module Rails
module Generators module Generators
class MigrationGenerator < NamedBase #metagenerator class MigrationGenerator < NamedBase # :nodoc:
argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
hook_for :orm, :required => true hook_for :orm, :required => true
end end
......
module Rails module Rails
module Generators module Generators
class ModelGenerator < NamedBase #metagenerator class ModelGenerator < NamedBase # :nodoc:
argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
hook_for :orm, :required => true hook_for :orm, :required => true
end end
......
module Rails module Rails
module Generators module Generators
class ObserverGenerator < NamedBase #metagenerator class ObserverGenerator < NamedBase # :nodoc:
hook_for :orm, :required => true hook_for :orm, :required => true
end end
end end
......
module Rails module Rails
module Generators module Generators
class PerformanceTestGenerator < NamedBase class PerformanceTestGenerator < NamedBase # :nodoc:
hook_for :performance_tool, :as => :performance hook_for :performance_tool, :as => :performance
end end
end end
......
...@@ -3,6 +3,13 @@ ...@@ -3,6 +3,13 @@
require 'date' require 'date'
module Rails module Rails
# The plugin builder allows you to override elements of the plugin
# generator without being forced to reverse the operations of the default
# generator.
#
# This allows you to override entire operations, like the creation of the
# Gemfile, README, or JavaScript files, without needing to know exactly
# what those operations do so you can create another template action.
class PluginBuilder class PluginBuilder
def rakefile def rakefile
template "Rakefile" template "Rakefile"
...@@ -146,7 +153,7 @@ def gemfile_entry ...@@ -146,7 +153,7 @@ def gemfile_entry
end end
module Generators module Generators
class PluginNewGenerator < AppBase class PluginNewGenerator < AppBase # :nodoc:
add_shared_options_for "plugin" add_shared_options_for "plugin"
alias_method :plugin_path, :app_path alias_method :plugin_path, :app_path
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
module Rails module Rails
module Generators module Generators
class ResourceGenerator < ModelGenerator #metagenerator class ResourceGenerator < ModelGenerator # :nodoc:
include ResourceHelpers include ResourceHelpers
hook_for :resource_controller, :required => true do |controller| hook_for :resource_controller, :required => true do |controller|
......
module Rails module Rails
module Generators module Generators
class ResourceRouteGenerator < NamedBase class ResourceRouteGenerator < NamedBase # :nodoc:
# Properly nests namespaces passed into a generator # Properly nests namespaces passed into a generator
# #
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Rails module Rails
module Generators module Generators
class ScaffoldGenerator < ResourceGenerator #metagenerator class ScaffoldGenerator < ResourceGenerator # :nodoc:
remove_hook_for :resource_controller remove_hook_for :resource_controller
remove_class_option :actions remove_class_option :actions
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Rails module Rails
module Generators module Generators
class ScaffoldControllerGenerator < NamedBase class ScaffoldControllerGenerator < NamedBase # :nodoc:
include ResourceHelpers include ResourceHelpers
check_class_collision :suffix => "Controller" check_class_collision :suffix => "Controller"
......
module Rails module Rails
module Generators module Generators
class TaskGenerator < NamedBase class TaskGenerator < NamedBase # :nodoc:
argument :actions, :type => :array, :default => [], :banner => "action action" argument :actions, :type => :array, :default => [], :banner => "action action"
def create_task_files def create_task_files
......
...@@ -4,8 +4,7 @@ module Rails ...@@ -4,8 +4,7 @@ module Rails
module Generators module Generators
# Deal with controller names on scaffold and add some helpers to deal with # Deal with controller names on scaffold and add some helpers to deal with
# ActiveModel. # ActiveModel.
# module ResourceHelpers # :nodoc:
module ResourceHelpers
mattr_accessor :skip_warn mattr_accessor :skip_warn
def self.included(base) #:nodoc: def self.included(base) #:nodoc:
...@@ -13,7 +12,6 @@ def self.included(base) #:nodoc: ...@@ -13,7 +12,6 @@ def self.included(base) #:nodoc:
end end
# Set controller variables on initialization. # Set controller variables on initialization.
#
def initialize(*args) #:nodoc: def initialize(*args) #:nodoc:
super super
......
...@@ -26,7 +26,6 @@ module Generators ...@@ -26,7 +26,6 @@ module Generators
# destination File.expand_path("../tmp", File.dirname(__FILE__)) # destination File.expand_path("../tmp", File.dirname(__FILE__))
# setup :prepare_destination # setup :prepare_destination
# end # end
#
class TestCase < ActiveSupport::TestCase class TestCase < ActiveSupport::TestCase
include FileUtils include FileUtils
...@@ -37,13 +36,13 @@ class TestCase < ActiveSupport::TestCase ...@@ -37,13 +36,13 @@ class TestCase < ActiveSupport::TestCase
self.current_path = File.expand_path(Dir.pwd) self.current_path = File.expand_path(Dir.pwd)
self.default_arguments = [] self.default_arguments = []
def setup def setup # :nodoc:
destination_root_is_set? destination_root_is_set?
ensure_current_path ensure_current_path
super super
end end
def teardown def teardown # :nodoc:
ensure_current_path ensure_current_path
super super
end end
...@@ -51,7 +50,6 @@ def teardown ...@@ -51,7 +50,6 @@ def teardown
# Sets which generator should be tested: # Sets which generator should be tested:
# #
# tests AppGenerator # tests AppGenerator
#
def self.tests(klass) def self.tests(klass)
self.generator_class = klass self.generator_class = klass
end end
...@@ -60,7 +58,6 @@ def self.tests(klass) ...@@ -60,7 +58,6 @@ def self.tests(klass)
# invoking it. # invoking it.
# #
# arguments %w(app_name --skip-active-record) # arguments %w(app_name --skip-active-record)
#
def self.arguments(array) def self.arguments(array)
self.default_arguments = array self.default_arguments = array
end end
...@@ -68,7 +65,6 @@ def self.arguments(array) ...@@ -68,7 +65,6 @@ def self.arguments(array)
# Sets the destination of generator files: # Sets the destination of generator files:
# #
# destination File.expand_path("../tmp", File.dirname(__FILE__)) # destination File.expand_path("../tmp", File.dirname(__FILE__))
#
def self.destination(path) def self.destination(path)
self.destination_root = path self.destination_root = path
end end
...@@ -91,7 +87,6 @@ def self.destination(path) ...@@ -91,7 +87,6 @@ def self.destination(path)
# assert_match(/Product\.all/, index) # assert_match(/Product\.all/, index)
# end # end
# end # end
#
def assert_file(relative, *contents) def assert_file(relative, *contents)
absolute = File.expand_path(relative, destination_root) absolute = File.expand_path(relative, destination_root)
assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not" assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not"
...@@ -114,7 +109,6 @@ def assert_file(relative, *contents) ...@@ -114,7 +109,6 @@ def assert_file(relative, *contents)
# path relative to the configured destination: # path relative to the configured destination:
# #
# assert_no_file "config/random.rb" # assert_no_file "config/random.rb"
#
def assert_no_file(relative) def assert_no_file(relative)
absolute = File.expand_path(relative, destination_root) absolute = File.expand_path(relative, destination_root)
assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does" assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does"
...@@ -132,7 +126,6 @@ def assert_no_file(relative) ...@@ -132,7 +126,6 @@ def assert_no_file(relative)
# assert_file "db/migrate/003_create_products.rb" # assert_file "db/migrate/003_create_products.rb"
# #
# Consequently, assert_migration accepts the same arguments has assert_file. # Consequently, assert_migration accepts the same arguments has assert_file.
#
def assert_migration(relative, *contents, &block) def assert_migration(relative, *contents, &block)
file_name = migration_file_name(relative) file_name = migration_file_name(relative)
assert file_name, "Expected migration #{relative} to exist, but was not found" assert file_name, "Expected migration #{relative} to exist, but was not found"
...@@ -143,7 +136,6 @@ def assert_migration(relative, *contents, &block) ...@@ -143,7 +136,6 @@ def assert_migration(relative, *contents, &block)
# path relative to the configured destination: # path relative to the configured destination:
# #
# assert_no_migration "db/migrate/create_products.rb" # assert_no_migration "db/migrate/create_products.rb"
#
def assert_no_migration(relative) def assert_no_migration(relative)
file_name = migration_file_name(relative) file_name = migration_file_name(relative)
assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}" assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
...@@ -158,7 +150,6 @@ def assert_no_migration(relative) ...@@ -158,7 +150,6 @@ def assert_no_migration(relative)
# assert_match(/create_table/, up) # assert_match(/create_table/, up)
# end # end
# end # end
#
def assert_class_method(method, content, &block) def assert_class_method(method, content, &block)
assert_instance_method "self.#{method}", content, &block assert_instance_method "self.#{method}", content, &block
end end
...@@ -171,7 +162,6 @@ def assert_class_method(method, content, &block) ...@@ -171,7 +162,6 @@ def assert_class_method(method, content, &block)
# assert_match(/Product\.all/, index) # assert_match(/Product\.all/, index)
# end # end
# end # end
#
def assert_instance_method(method, content) def assert_instance_method(method, content)
assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}" assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}"
yield $2.strip if block_given? yield $2.strip if block_given?
...@@ -182,7 +172,6 @@ def assert_instance_method(method, content) ...@@ -182,7 +172,6 @@ def assert_instance_method(method, content)
# properly: # properly:
# #
# assert_field_type :date, :date_select # assert_field_type :date, :date_select
#
def assert_field_type(attribute_type, field_type) def assert_field_type(attribute_type, field_type)
assert_equal(field_type, create_generated_attribute(attribute_type).field_type) assert_equal(field_type, create_generated_attribute(attribute_type).field_type)
end end
...@@ -190,7 +179,6 @@ def assert_field_type(attribute_type, field_type) ...@@ -190,7 +179,6 @@ def assert_field_type(attribute_type, field_type)
# Asserts the given attribute type gets a proper default value: # Asserts the given attribute type gets a proper default value:
# #
# assert_field_default_value :string, "MyString" # assert_field_default_value :string, "MyString"
#
def assert_field_default_value(attribute_type, value) def assert_field_default_value(attribute_type, value)
assert_equal(value, create_generated_attribute(attribute_type).default) assert_equal(value, create_generated_attribute(attribute_type).default)
end end
...@@ -224,27 +212,26 @@ def generator(args=self.default_arguments, options={}, config={}) ...@@ -224,27 +212,26 @@ def generator(args=self.default_arguments, options={}, config={})
# attribute type and, optionally, the attribute name: # attribute type and, optionally, the attribute name:
# #
# create_generated_attribute(:string, 'name') # create_generated_attribute(:string, 'name')
#
def create_generated_attribute(attribute_type, name = 'test', index = nil) def create_generated_attribute(attribute_type, name = 'test', index = nil)
Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':'))
end end
protected protected
def destination_root_is_set? #:nodoc: def destination_root_is_set? # :nodoc:
raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root
end end
def ensure_current_path #:nodoc: def ensure_current_path # :nodoc:
cd current_path cd current_path
end end
def prepare_destination def prepare_destination # :nodoc:
rm_rf(destination_root) rm_rf(destination_root)
mkdir_p(destination_root) mkdir_p(destination_root)
end end
def migration_file_name(relative) #:nodoc: def migration_file_name(relative) # :nodoc:
absolute = File.expand_path(relative, destination_root) absolute = File.expand_path(relative, destination_root)
dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '') dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '')
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
......
require 'rails/generators/named_base' require 'rails/generators/named_base'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class Base < Rails::Generators::NamedBase #:nodoc: class Base < Rails::Generators::NamedBase # :nodoc:
end end
end end
end end
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class ControllerGenerator < Base class ControllerGenerator < Base # :nodoc:
argument :actions, :type => :array, :default => [], :banner => "action action" argument :actions, :type => :array, :default => [], :banner => "action action"
check_class_collision :suffix => "ControllerTest" check_class_collision :suffix => "ControllerTest"
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class HelperGenerator < Base class HelperGenerator < Base # :nodoc:
check_class_collision :suffix => "HelperTest" check_class_collision :suffix => "HelperTest"
def create_helper_files def create_helper_files
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class IntegrationGenerator < Base class IntegrationGenerator < Base # :nodoc:
check_class_collision :suffix => "Test" check_class_collision :suffix => "Test"
def create_test_files def create_test_files
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class MailerGenerator < Base class MailerGenerator < Base # :nodoc:
argument :actions, :type => :array, :default => [], :banner => "method method" argument :actions, :type => :array, :default => [], :banner => "method method"
check_class_collision :suffix => "Test" check_class_collision :suffix => "Test"
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class ModelGenerator < Base class ModelGenerator < Base # :nodoc:
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
class_option :fixture, :type => :boolean class_option :fixture, :type => :boolean
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class ObserverGenerator < Base class ObserverGenerator < Base # :nodoc:
check_class_collision :suffix => "ObserverTest" check_class_collision :suffix => "ObserverTest"
def create_test_files def create_test_files
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class PerformanceGenerator < Base class PerformanceGenerator < Base # :nodoc:
check_class_collision :suffix => "Test" check_class_collision :suffix => "Test"
def create_test_files def create_test_files
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class PluginGenerator < Base class PluginGenerator < Base # :nodoc:
check_class_collision :suffix => "Test" check_class_collision :suffix => "Test"
def create_test_files def create_test_files
......
require 'rails/generators/test_unit' require 'rails/generators/test_unit'
require 'rails/generators/resource_helpers' require 'rails/generators/resource_helpers'
module TestUnit module TestUnit # :nodoc:
module Generators module Generators # :nodoc:
class ScaffoldGenerator < Base class ScaffoldGenerator < Base # :nodoc:
include Rails::Generators::ResourceHelpers include Rails::Generators::ResourceHelpers
check_class_collision :suffix => "ControllerTest" check_class_collision :suffix => "ControllerTest"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册