railties 3.0.0.beta3 → 3.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/CHANGELOG +5 -0
  2. data/README +118 -123
  3. data/guides/source/3_0_release_notes.textile +13 -11
  4. data/guides/source/action_controller_overview.textile +2 -2
  5. data/guides/source/action_mailer_basics.textile +70 -26
  6. data/guides/source/action_view_overview.textile +1 -1
  7. data/guides/source/active_record_basics.textile +9 -1
  8. data/guides/source/active_record_querying.textile +2 -2
  9. data/guides/source/active_support_core_extensions.textile +377 -9
  10. data/guides/source/activerecord_validations_callbacks.textile +98 -55
  11. data/guides/source/association_basics.textile +1 -1
  12. data/guides/source/caching_with_rails.textile +1 -1
  13. data/guides/source/command_line.textile +23 -23
  14. data/guides/source/configuring.textile +1 -3
  15. data/guides/source/contribute.textile +27 -28
  16. data/guides/source/credits.html.erb +4 -4
  17. data/guides/source/debugging_rails_applications.textile +2 -2
  18. data/guides/source/form_helpers.textile +7 -6
  19. data/guides/source/generators.textile +19 -29
  20. data/guides/source/getting_started.textile +106 -49
  21. data/guides/source/i18n.textile +27 -27
  22. data/guides/source/index.html.erb +18 -8
  23. data/guides/source/initialization.textile +140 -514
  24. data/guides/source/layout.html.erb +6 -4
  25. data/guides/source/layouts_and_rendering.textile +5 -5
  26. data/guides/source/migrations.textile +7 -3
  27. data/guides/source/nested_model_forms.textile +2 -2
  28. data/guides/source/performance_testing.textile +11 -12
  29. data/guides/source/plugins.textile +30 -30
  30. data/guides/source/rails_application_templates.textile +3 -3
  31. data/guides/source/rails_on_rack.textile +3 -66
  32. data/guides/source/routing.textile +10 -4
  33. data/guides/source/security.textile +1 -1
  34. data/guides/source/testing.textile +55 -52
  35. data/guides/w3c_validator.rb +67 -0
  36. data/lib/rails.rb +1 -0
  37. data/lib/rails/application.rb +49 -13
  38. data/lib/rails/application/bootstrap.rb +7 -6
  39. data/lib/rails/application/configuration.rb +24 -47
  40. data/lib/rails/application/finisher.rb +8 -3
  41. data/lib/rails/backtrace_cleaner.rb +11 -12
  42. data/lib/rails/commands.rb +54 -54
  43. data/lib/rails/commands/application.rb +7 -2
  44. data/lib/rails/commands/{performance/benchmarker.rb → benchmarker.rb} +0 -0
  45. data/lib/rails/commands/dbconsole.rb +4 -3
  46. data/lib/rails/commands/destroy.rb +1 -0
  47. data/lib/rails/commands/generate.rb +1 -0
  48. data/lib/rails/commands/{performance/profiler.rb → profiler.rb} +0 -0
  49. data/lib/rails/commands/runner.rb +4 -2
  50. data/lib/rails/configuration.rb +36 -0
  51. data/lib/rails/engine.rb +24 -24
  52. data/lib/rails/engine/configuration.rb +0 -1
  53. data/lib/rails/generators.rb +48 -10
  54. data/lib/rails/generators/actions.rb +5 -3
  55. data/lib/rails/generators/base.rb +23 -17
  56. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb +9 -8
  57. data/lib/rails/generators/erb/scaffold/templates/show.html.erb +1 -1
  58. data/lib/rails/generators/generated_attribute.rb +7 -6
  59. data/lib/rails/generators/rails/app/USAGE +2 -2
  60. data/lib/rails/generators/rails/app/app_generator.rb +242 -97
  61. data/lib/rails/generators/rails/app/templates/Gemfile +3 -0
  62. data/lib/rails/generators/rails/app/templates/README +167 -130
  63. data/lib/rails/generators/rails/app/templates/Rakefile +0 -3
  64. data/lib/rails/generators/rails/app/templates/config/boot.rb +9 -2
  65. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +5 -5
  66. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +4 -0
  67. data/lib/rails/generators/rails/app/templates/script/rails +2 -5
  68. data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +1 -3
  69. data/lib/rails/generators/rails/stylesheets/templates/scaffold.css +5 -9
  70. data/lib/rails/generators/test_case.rb +12 -0
  71. data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +1 -1
  72. data/lib/rails/generators/test_unit/performance/templates/performance_test.rb +1 -1
  73. data/lib/rails/info.rb +0 -33
  74. data/lib/rails/log_subscriber.rb +13 -6
  75. data/lib/rails/rack/logger.rb +4 -3
  76. data/lib/rails/railtie.rb +4 -0
  77. data/lib/rails/railtie/configuration.rb +21 -4
  78. data/lib/rails/tasks/documentation.rake +2 -0
  79. data/lib/rails/tasks/framework.rake +22 -0
  80. data/lib/rails/tasks/middleware.rake +1 -1
  81. data/lib/rails/tasks/routes.rake +5 -1
  82. data/lib/rails/test_help.rb +3 -1
  83. data/lib/rails/test_unit/testing.rake +3 -1
  84. data/lib/rails/version.rb +1 -1
  85. metadata +12 -19
  86. data/lib/rails/application/metal_loader.rb +0 -50
  87. data/lib/rails/dispatcher.rb +0 -24
  88. data/lib/rails/generators/rails/mailer/USAGE +0 -15
  89. data/lib/rails/generators/rails/mailer/mailer_generator.rb +0 -14
  90. data/lib/rails/generators/rails/mailer/templates/mailer.rb +0 -16
  91. data/lib/rails/generators/rails/metal/USAGE +0 -8
  92. data/lib/rails/generators/rails/metal/metal_generator.rb +0 -11
  93. data/lib/rails/generators/rails/metal/templates/metal.rb +0 -12
@@ -91,7 +91,7 @@ The +params+ hash is not limited to one-dimensional keys and values. It can cont
91
91
  GET /clients?ids[]=1&ids[]=2&ids[]=3
92
92
  </pre>
93
93
 
94
- NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5b=3" as "[" and "]" are not allowed in URLs. Most of the time you don't have to worry about this because the browser will take care of it for you, and Rails will decode it back when it receives it, but if you ever find yourself having to send those requests to the server manually you have to keep this in mind.
94
+ NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3" as "[" and "]" are not allowed in URLs. Most of the time you don't have to worry about this because the browser will take care of it for you, and Rails will decode it back when it receives it, but if you ever find yourself having to send those requests to the server manually you have to keep this in mind.
95
95
 
96
96
  The value of +params[:ids]+ will now be +["1", "2", "3"]+. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.
97
97
 
@@ -653,7 +653,7 @@ class ClientsController < ApplicationController
653
653
  # Stream a file that has already been generated and stored on disk.
654
654
  def download_pdf
655
655
  client = Client.find(params[:id])
656
- send_data("#{Rails.root}/files/clients/#{client.id}.pdf",
656
+ send_file("#{Rails.root}/files/clients/#{client.id}.pdf",
657
657
  :filename => "#{client.name}.pdf",
658
658
  :type => "application/pdf")
659
659
  end
@@ -55,12 +55,12 @@ class UserMailer < ActionMailer::Base
55
55
  end
56
56
  </ruby>
57
57
 
58
- Here is a quick explanation of the items presented in the preceding method. For a full list of all available options, please have a look further down at the Complete List of ActionMailer user-settable attributes section.
58
+ Here is a quick explanation of the items presented in the preceding method. For a full list of all available options, please have a look further down at the Complete List of Action Mailer user-settable attributes section.
59
59
 
60
60
  * <tt>default Hash</tt> - This is a hash of default values for any email you send, in this case we are setting the <tt>:from</tt> header to a value for all messages in this class, this can be overridden on a per email basis
61
- * +mail+ - The actual email message, we are passing the <tt>:to</tt> and <tt>:subject</tt> headers in|
61
+ * +mail+ - The actual email message, we are passing the <tt>:to</tt> and <tt>:subject</tt> headers in.
62
62
 
63
- And instance variables we define in the method become available for use in the view.
63
+ Just like controllers, any instance variables we define in the method become available for use in the views.
64
64
 
65
65
  h5. Create a Mailer View
66
66
 
@@ -104,9 +104,9 @@ When you call the +mail+ method now, Action Mailer will detect the two templates
104
104
 
105
105
  h5. Wire It Up So That the System Sends the Email When a User Signs Up
106
106
 
107
- There are three ways to achieve this. One is to send the email from the controller that sends the email, another is to put it in a +before_create+ callback in the user model, and the last one is to use an observer on the user model. Whether you use the second or third methods is up to you, but staying away from the first is recommended. Not because it's wrong, but because it keeps your controller clean, and keeps all logic related to the user model within the user model. This way, whichever way a user is created (from a web form, or from an API call, for example), we are guaranteed that the email will be sent.
107
+ There are several ways to do this, some people create Rails Observers to fire off emails, others do it inside of the User Model. However, in Rails 3, mailers are really just another way to render a view. Instead of rendering a view and sending out the HTTP protocol, they are just sending it out through the Email protocols instead. Due to this, it makes sense to just have your controller tell the mailer to send an email when a user is successfully created.
108
108
 
109
- Let's see how we would go about wiring it up using an observer.
109
+ Setting this up is painfully simple.
110
110
 
111
111
  First off, we need to create a simple +User+ scaffold:
112
112
 
@@ -115,35 +115,46 @@ $ rails generate scaffold user name:string email:string login:string
115
115
  $ rake db:migrate
116
116
  </shell>
117
117
 
118
- Now that we have a user model to play with, edit +config/application.rb+ and register the observer:
118
+ Now that we have a user model to play with, we will just edit the +app/controllers/users_controller.rb+ make it instruct the UserMailer to deliver an email to the newly created user by editing the create action and inserting a call to <tt>UserMailer.welcome_email</tt> right after the user is successfully saved:
119
119
 
120
120
  <ruby>
121
- module MailerGuideCode
122
- class Application < Rails::Application
123
- # ...
124
- config.active_record.observers = :user_observer
121
+ class UsersController < ApplicationController
122
+ # POST /users
123
+ # POST /users.xml
124
+ def create
125
+ @user = User.new(params[:user])
126
+
127
+ respond_to do |format|
128
+ if @user.save
129
+ # Tell the UserMailer to send a welcome Email after save
130
+ UserMailer.welcome_email(@user).deliver
131
+
132
+ format.html { redirect_to(@user, :notice => 'User was successfully created.') }
133
+ format.xml { render :xml => @user, :status => :created, :location => @user }
134
+ else
135
+ format.html { render :action => "new" }
136
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
137
+ end
138
+ end
125
139
  end
126
140
  end
127
141
  </ruby>
128
142
 
129
- You can make a +app/observers+ directory and Rails will automatically load it for you (Rails will automatically load anything in the +app+ directory as of version 3.0)
143
+ This provides a much simpler implementation that does not require the registering of observers and the like.
130
144
 
131
- Now create a file called +user_observer.rb+ in +app/observers+ and make it look like:
145
+ The method +welcome_email+ returns a Mail::Message object which can then just be told +deliver+ to send itself out.
132
146
 
133
- <ruby>
134
- class UserObserver < ActiveRecord::Observer
135
- def after_create(user)
136
- UserMailer.welcome_email(user).deliver
137
- end
138
- end
139
- </ruby>
147
+ NOTE: In previous versions of Rails, you would call +deliver_welcome_email+ or +create_welcome_email+ however in Rails 3.0 this has been deprecated in favour of just calling the method name itself.
140
148
 
141
- Notice how we call <tt>UserMailer.welcome_email(user)</tt>? Even though in the <tt>user_mailer.rb</tt> file we defined an instance method, we are calling the method_name +welcome_email(user)+ on the class. This is a peculiarity of Action Mailer.
149
+ WARNING: Sending out one email should only take a fraction of a second, if you are planning on sending out many emails, or you have a slow domain resolution service, you might want to investigate using a background process like delayed job.
142
150
 
143
- NOTE: In previous versions of Rails, you would call +deliver_welcome_email+ or +create_welcome_email+ however in Rails 3.0 this has been deprecated in favour of just calling the method name itself.
151
+ h4. Auto encoding header values
144
152
 
145
- The method +welcome_email+ returns a Mail::Message object which can then just be told +deliver+ to send itself out.
153
+ Action Mailer now handles the auto encoding of multibyte characters inside of headers and bodies.
146
154
 
155
+ If you are using UTF-8 as your character set, you do not have to do anything special, just go ahead and send in UTF-8 data to the address fields, subject, keywords, filenames or body of the email and ActionMailer will auto encode it into quoted printable for you in the case of a header field or Base64 encode any body parts that are non US-ASCII.
156
+
157
+ For more complex examples, such as defining alternate character sets or self encoding text first, please refer to the Mail library.
147
158
 
148
159
  h4. Complete List of Action Mailer Methods
149
160
 
@@ -160,21 +171,23 @@ Defining custom headers are simple, you can do it one of three ways:
160
171
  * Defining a header field as a parameter to the +mail+ method:
161
172
 
162
173
  <ruby>
163
- mail(:x_spam => value)
174
+ mail("X-Spam" => value)
164
175
  </ruby>
165
176
 
166
177
  * Passing in a key value assignment to the +headers+ method:
167
178
 
168
179
  <ruby>
169
- headers[:x_spam] = value
180
+ headers["X-Spam"] = value
170
181
  </ruby>
171
182
 
172
183
  * Passing a hash of key value pairs to the +headers+ method:
173
184
 
174
185
  <ruby>
175
- headers {:x_spam => value, :x_special => another_value}
186
+ headers {"X-Spam" => value, "X-Special" => another_value}
176
187
  </ruby>
177
188
 
189
+ TIP: All <tt>X-Value</tt> headers per the RFC2822 can appear more than one time. If you want to delete an <tt>X-Value</tt> header, you need to assign it a value of <tt>nil</tt>.
190
+
178
191
  h5. Adding Attachments
179
192
 
180
193
  Adding attachments has been simplified in Action Mailer 3.0.
@@ -198,6 +211,37 @@ attachments['filename.jpg'] = {:mime_type => 'application/x-gzip',
198
211
 
199
212
  NOTE: If you specify an encoding, Mail will assume that your content is already encoded and not try to Base64 encode it.
200
213
 
214
+ h5. Making Inline Attachments
215
+
216
+ Inline attachments are now possible in ActionMailer. While previously in the pre 3.0 version of Rails, you could do inline attachments, it involved a lot of hacking and determination to pull it off.
217
+
218
+ ActionMailer now makes inline attachments as trivial as they should be.
219
+
220
+ * Firstly, to tell Mail to turn an attachment into an inline attachment, you just call <tt>#inline</tt> on the attachments method within your Mailer:
221
+
222
+ <ruby>
223
+ def welcome
224
+ attachments.inline['image.jpg'] = File.read('/path/to/image.jpg')
225
+ end
226
+ </ruby>
227
+
228
+ * Then in your view, you can just reference <tt>attachments[]</tt> as a hash and specify which attachment you want to show, calling +url+ on it and then passing the result into the <tt>image_tag</tt> method:
229
+
230
+ <erb>
231
+ <p>Hello there, this is our image</p>
232
+
233
+ <%= image_tag attachments['image.jpg'].url %>
234
+ </erb>
235
+
236
+ * As this is a standard call to +image_tag+ you can pass in an options hash after the attachment url as you could for any other image:
237
+
238
+ <erb>
239
+ <p>Hello there, this is our image</p>
240
+
241
+ <%= image_tag attachments['image.jpg'].url, :alt => 'My Photo',
242
+ :class => 'photos' %>
243
+ </erb>
244
+
201
245
  h4. Mailer Views
202
246
 
203
247
  Mailer views are located in the +app/views/name_of_mailer_class+ directory. The specific mailer view is known to the class because it's name is the same as the mailer method. So for example, in our example from above, our mailer view for the +welcome_email+ method will be in +app/views/user_mailer/welcome_email.html.erb+ for the HTML version and +welcome_email.text.erb+ for the plain text version.
@@ -325,7 +369,7 @@ class UserMailer < ActionMailer::Base
325
369
  end
326
370
  </ruby>
327
371
 
328
- The above will send a multipart email with an attachment, properly nested with the top level being <tt>mixed/multipart</tt> and the first part being a <tt>mixed/alternative</tt> containing the plain text and HTML email messages.
372
+ The above will send a multipart email with an attachment, properly nested with the top level being <tt>multipart/mixed</tt> and the first part being a <tt>multipart/alternative</tt> containing the plain text and HTML email messages.
329
373
 
330
374
  h3. Receiving Emails
331
375
 
@@ -699,7 +699,7 @@ Creates a scope around a specific model object like form_for, but doesn‘t crea
699
699
  First name: <%= person_form.text_field :first_name %>
700
700
  Last name : <%= person_form.text_field :last_name %>
701
701
 
702
- <% fields_for @person.permission do |permission_fields| %>
702
+ <%= fields_for @person.permission do |permission_fields| %>
703
703
  Admin? : <%= permission_fields.check_box :admin %>
704
704
  <% end %>
705
705
  <% end %>
@@ -104,6 +104,14 @@ class Product < ActiveRecord::Base
104
104
  set_table_name "PRODUCT"
105
105
  end
106
106
  </ruby>
107
+ If you do so, you will have to define manually the class name that is hosting the fixtures (class_name.yml) using the +set_fixture_class+ method in your test definition:
108
+ <ruby>
109
+ class FunnyJoke < ActiveSupport::TestCase
110
+ set_fixture_class :funny_jokes => 'Joke'
111
+ fixtures :funny_jokes
112
+ ...
113
+ end
114
+ </ruby>
107
115
 
108
116
  It's also possible to override the column that should be used as the table's primary key. Use the +ActiveRecord::Base.set_primary_key+ method for that:
109
117
  <ruby>
@@ -201,4 +209,4 @@ Active Record callbacks allow you to attach code to certain events in the life-c
201
209
 
202
210
  h3. Migrations
203
211
 
204
- Rails provides a domain-specific language for managing a database schema called migrations. Migrations are stored in files which are executed against any database that Active Record support using rake. Rails keeps track of which files have been committed to the database and provides rollback features. You can learn more about migrations in the "Active Record Migrations guide":migrations.html
212
+ Rails provides a domain-specific language for managing a database schema called migrations. Migrations are stored in files which are executed against any database that Active Record support using rake. Rails keeps track of which files have been committed to the database and provides rollback features. You can learn more about migrations in the "Active Record Migrations guide":migrations.html
@@ -17,7 +17,7 @@ If you're used to using raw SQL to find database records then, generally, you wi
17
17
 
18
18
  Code examples throughout this guide will refer to one or more of the following models:
19
19
 
20
- TIP: All of the following models uses +id+ as the primary key, unless specified otherwise.
20
+ TIP: All of the following models use +id+ as the primary key, unless specified otherwise.
21
21
 
22
22
  <br />
23
23
 
@@ -802,7 +802,7 @@ will either assign an existing client object with the name "Ryan" to the client
802
802
 
803
803
  h3. Finding by SQL
804
804
 
805
- If you'd like to use your own SQL to find records in a table you can use +find_by_sql+. The +find_by_sql+ method will return an array of objects even the underlying query returns just a single record. For example you could run this query:
805
+ If you'd like to use your own SQL to find records in a table you can use +find_by_sql+. The +find_by_sql+ method will return an array of objects even if the underlying query returns just a single record. For example you could run this query:
806
806
 
807
807
  <ruby>
808
808
  Client.find_by_sql("SELECT * FROM clients
@@ -1254,6 +1254,39 @@ There's also the destructive version +String#squish!+.
1254
1254
 
1255
1255
  NOTE: Defined in +active_support/core_ext/string/filters.rb+.
1256
1256
 
1257
+ h4. +truncate+
1258
+
1259
+ The method +truncate+ returns a copy of its receiver truncated after a given +length+:
1260
+
1261
+ <ruby>
1262
+ "Oh dear! Oh dear! I shall be late!".truncate(20)
1263
+ # => "Oh dear! Oh dear!..."
1264
+ </ruby>
1265
+
1266
+ Ellipsis can be customized with the +:omission+ option:
1267
+
1268
+ <ruby>
1269
+ "Oh dear! Oh dear! I shall be late!".truncate(20, :omission => '&hellip;')
1270
+ # => "Oh dear! Oh &hellip;"
1271
+ </ruby>
1272
+
1273
+ Note in particular that truncation takes into account the length of the omission string.
1274
+
1275
+ Pass a +:separator+ to truncate the string at a natural break:
1276
+
1277
+ <ruby>
1278
+ "Oh dear! Oh dear! I shall be late!".truncate(18)
1279
+ # => "Oh dear! Oh dea..."
1280
+ "Oh dear! Oh dear! I shall be late!".truncate(18, :separator => ' ')
1281
+ # => "Oh dear! Oh..."
1282
+ </ruby>
1283
+
1284
+ In the above example "dear" gets cut first, but then +:separator+ prevents it.
1285
+
1286
+ WARNING: The option +:separator+ can't be a regexp.
1287
+
1288
+ NOTE: Defined in +active_support/core_ext/string/filters.rb+.
1289
+
1257
1290
  h4. Key-based Interpolation
1258
1291
 
1259
1292
  In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:
@@ -1894,13 +1927,21 @@ Similarly, +from+ returns the tail from the element at the passed index on:
1894
1927
 
1895
1928
  The methods +second+, +third+, +fourth+, and +fifth+ return the corresponding element (+first+ is builtin). Thanks to social wisdom and positive constructiveness all around, +forty_two+ is also available.
1896
1929
 
1897
- You can pick a random element with +rand+:
1930
+ NOTE: Defined in +active_support/core_ext/array/access.rb+.
1931
+
1932
+ h4. Random Access
1933
+
1934
+ Active Support backports +sample+ from Ruby 1.9:
1898
1935
 
1899
1936
  <ruby>
1900
- shape_type = [Circle, Square, Triangle].rand
1937
+ shape_type = [Circle, Square, Triangle].sample
1938
+ # => Square, for example
1939
+
1940
+ shape_types = [Circle, Square, Triangle].sample(2)
1941
+ # => [Triangle, Circle], for example
1901
1942
  </ruby>
1902
1943
 
1903
- NOTE: Defined in +active_support/core_ext/array/access.rb+.
1944
+ NOTE: Defined in +active_support/core_ext/array/random_access.rb+.
1904
1945
 
1905
1946
  h4. Options Extraction
1906
1947
 
@@ -2648,21 +2689,348 @@ NOTE: Defined in +active_support/core_ext/proc.rb+.
2648
2689
 
2649
2690
  h3. Extensions to +Date+
2650
2691
 
2651
- ...
2692
+ h4. Calculations
2693
+
2694
+ NOTE: All the following methods are defined in +active_support/core_ext/date/calculations.rb+.
2695
+
2696
+ INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, +Date.new(1582, 10, 4).tomorrow+ returns +Date.new(1582, 10, 15)+ and so on. Please check +test/core_ext/date_ext_test.rb+ in the Active Support test suite for expected behavior.
2697
+
2698
+ h5. +Date.current+
2699
+
2700
+ Active Support defines +Date.current+ to be today in the current time zone. That's like +Date.today+, except that it honors the user time zone, if defined. It also defines +Date.yesterday+ and +Date.tomorrow+, and the instance predicates +past?+, +today?+, and +future?+, all of them relative to +Date.current+.
2701
+
2702
+ h5. Named dates
2703
+
2704
+ h6. +prev_year+, +next_year+
2705
+
2706
+ In Ruby 1.9 +prev_year+ and +next_year+ return a date with the same day/month in the last or next year:
2707
+
2708
+ <ruby>
2709
+ d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
2710
+ d.prev_year # => Fri, 08 May 2009
2711
+ d.next_year # => Sun, 08 May 2011
2712
+ </ruby>
2713
+
2714
+ If date is the 29th of February of a leap year, you obtain the 28th:
2715
+
2716
+ <ruby>
2717
+ d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000
2718
+ d.prev_year # => Sun, 28 Feb 1999
2719
+ d.next_year # => Wed, 28 Feb 2001
2720
+ </ruby>
2721
+
2722
+ Active Support defines these methods as well for Ruby 1.8.
2723
+
2724
+ h6. +prev_month+, +next_month+
2725
+
2726
+ In Ruby 1.9 +prev_month+ and +next_month+ return the date with the same day in the last or next month:
2727
+
2728
+ <ruby>
2729
+ d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
2730
+ d.prev_month # => Thu, 08 Apr 2010
2731
+ d.next_month # => Tue, 08 Jun 2010
2732
+ </ruby>
2733
+
2734
+ If such a day does not exist, the last day of the corresponding month is returned:
2735
+
2736
+ <ruby>
2737
+ Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000
2738
+ Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000
2739
+ Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000
2740
+ Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000
2741
+ </ruby>
2742
+
2743
+ Active Support defines these methods as well for Ruby 1.8.
2744
+
2745
+ h6. +beginning_of_week+, +end_of_week+
2746
+
2747
+ The methods +beginning_of_week+ and +end_of_week+ return the dates for the beginning and end of week, assuming weeks start on Monday:
2748
+
2749
+ <ruby>
2750
+ d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
2751
+ d.beginning_of_week # => Mon, 03 May 2010
2752
+ d.end_of_week # => Sun, 09 May 2010
2753
+ </ruby>
2754
+
2755
+ +beginning_of_week+ is aliased to +monday+ and +at_beginning_of_week+. +end_of_week+ is aliased to +sunday+ and +at_end_of_week+.
2756
+
2757
+ h6. +next_week+
2758
+
2759
+ +next_week+ receives a symbol with a day name in English (in lowercase, default is +:monday+) and it returns the date corresponding to that day in the next week:
2760
+
2761
+ <ruby>
2762
+ d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
2763
+ d.next_week # => Mon, 10 May 2010
2764
+ d.next_week(:saturday) # => Sat, 15 May 2010
2765
+ </ruby>
2766
+
2767
+ h6. +beginning_of_month+, +end_of_month+
2768
+
2769
+ The methods +beginning_of_month+ and +end_of_month+ return the dates for the beginning and end of the month:
2770
+
2771
+ <ruby>
2772
+ d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
2773
+ d.beginning_of_month # => Sat, 01 May 2010
2774
+ d.end_of_month # => Mon, 31 May 2010
2775
+ </ruby>
2776
+
2777
+ +beginning_of_month+ is aliased to +at_beginning_of_month+, and +end_of_month+ is aliased to +at_end_of_month+.
2778
+
2779
+ h6. +beginning_of_quarter+, +end_of_quarter+
2780
+
2781
+ The methods +beginning_of_quarter+ and +end_of_quarter+ return the dates for the beginning and end of the quarter of the receiver's calendar year:
2782
+
2783
+ <ruby>
2784
+ d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
2785
+ d.beginning_of_quarter # => Thu, 01 Apr 2010
2786
+ d.end_of_quarter # => Wed, 30 Jun 2010
2787
+ </ruby>
2788
+
2789
+ +beginning_of_quarter+ is aliased to +at_beginning_of_quarter+, and +end_of_quarter+ is aliased to +at_end_of_quarter+.
2790
+
2791
+ h6. +beginning_of_year+, +end_of_year+
2792
+
2793
+ The methods +beginning_of_year+ and +end_of_year+ return the dates for the beginning and end of the year:
2794
+
2795
+ <ruby>
2796
+ d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
2797
+ d.beginning_of_year # => Fri, 01 Jan 2010
2798
+ d.end_of_year # => Fri, 31 Dec 2010
2799
+ </ruby>
2800
+
2801
+ +beginning_of_year+ is aliased to +at_beginning_of_year+, and +end_of_year+ is aliased to +at_end_of_year+.
2802
+
2803
+ h5. Other Date Computations
2804
+
2805
+ h6. +years_ago+, +years_since+
2806
+
2807
+ The method +years_ago+ receives a number of years and returns the same date those many years ago:
2808
+
2809
+ <ruby>
2810
+ date = Date.new(2010, 6, 7)
2811
+ date.years_ago(10) # => Wed, 07 Jun 2000
2812
+ </ruby>
2813
+
2814
+ +years_since+ moves forward in time:
2815
+
2816
+ <ruby>
2817
+ date = Date.new(2010, 6, 7)
2818
+ date.years_since(10) # => Sun, 07 Jun 2020
2819
+ </ruby>
2820
+
2821
+ If such a day does not exist, the last day of the corresponding month is returned:
2822
+
2823
+ <ruby>
2824
+ Date.new(2012, 2, 29).years_ago(3) # => Sat, 28 Feb 2009
2825
+ Date.new(2012, 2, 29).years_since(3) # => Sat, 28 Feb 2015
2826
+ </ruby>
2827
+
2828
+ h6. +months_ago+, +months_since+
2829
+
2830
+ The methods +months_ago+ and +months_since+ work analogously for months:
2831
+
2832
+ <ruby>
2833
+ Date.new(2010, 4, 30).months_ago(2) # => Sun, 28 Feb 2010
2834
+ Date.new(2010, 4, 30).months_since(2) # => Wed, 30 Jun 2010
2835
+ </ruby>
2836
+
2837
+ If such a day does not exist, the last day of the corresponding month is returned:
2838
+
2839
+ <ruby>
2840
+ Date.new(2010, 4, 30).months_ago(2) # => Sun, 28 Feb 2010
2841
+ Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010
2842
+ </ruby>
2843
+
2844
+ h6. +advance+
2845
+
2846
+ The most generic way to jump to other days is +advance+. This method receives a hash with keys +:years+, +:months+, +:weeks+, +:days+, and returns a date advanced as much as the present keys indicate:
2847
+
2848
+ <ruby>
2849
+ date = Date.new(2010, 6, 6)
2850
+ date.advance(:years => 1, :weeks => 2) # => Mon, 20 Jun 2011
2851
+ date.advance(:months => 2, :days => -2) # => Wed, 04 Aug 2010
2852
+ </ruby>
2853
+
2854
+ Note in the previous example that increments may be negative.
2855
+
2856
+ To perform the computation the method first increments years, then months, then weeks, and finally days. This order is important towards the end of months. Say for example we are at the end of February of 2010, and we want to move one month and one day forward.
2857
+
2858
+ The method +advance+ advances first one month, and the one day, the result is:
2859
+
2860
+ <ruby>
2861
+ Date.new(2010, 2, 28).advance(:months => 1, :day => 1)
2862
+ # => Sun, 28 Mar 2010
2863
+ </ruby>
2864
+
2865
+ While if it did it the other way around the result would be different:
2866
+
2867
+ <ruby>
2868
+ Date.new(2010, 2, 28).advance(:days => 1).advance(:months => 1)
2869
+ # => Thu, 01 Apr 2010
2870
+ </ruby>
2871
+
2872
+ h5. Changing Components
2873
+
2874
+ The method +change+ allows you to get a new date which is the same as the receiver except for the given year, month, or day:
2875
+
2876
+ <ruby>
2877
+ Date.new(2010, 12, 23).change(:year => 2011, :month => 11)
2878
+ # => Wed, 23 Nov 2011
2879
+ </ruby>
2880
+
2881
+ This method is not tolerant to non-existing dates, if the change is invalid +ArgumentError+ is raised:
2882
+
2883
+ <ruby>
2884
+ Date.new(2010, 1, 31).change(:month => 2)
2885
+ # => ArgumentError: invalid date
2886
+ </ruby>
2887
+
2888
+ h5. Named Times
2889
+
2890
+ WARNING: The following methods do not take into account the user time zone. They return timestamps in localtime.
2891
+
2892
+ INFO: The following methods return a +Time+ object if possible, otherwise a +DateTime+.
2893
+
2894
+ h6. +beginning_of_day+, +end_of_day+
2895
+
2896
+ The method +beginning_of_day+ returns a timestamp at the beginning of the day (00:00:00):
2897
+
2898
+ <ruby>
2899
+ date = Date.new(2010, 6, 7)
2900
+ date.beginning_of_day # => Sun Jun 07 00:00:00 +0200 2010
2901
+ </ruby>
2902
+
2903
+ The method +end_of_day+ returns a timestamp at the end of the day (23:59:59):
2904
+
2905
+ <ruby>
2906
+ date = Date.new(2010, 6, 7)
2907
+ date.end_of_day # => Sun Jun 06 23:59:59 +0200 2010
2908
+ </ruby>
2909
+
2910
+ +beginning_of_day+ is aliased to +at_beginning_of_day+, +midnight+, +at_midnight+
2911
+
2912
+ h4(#date-conversions). Conversions
2652
2913
 
2653
2914
  h3. Extensions to +DateTime+
2654
2915
 
2655
- ...
2916
+ NOTE: All the following methods are defined in +active_support/core_ext/date_time/calculations.rb+.
2656
2917
 
2657
- h3. Extensions to +Time+
2918
+ WARNING: +DateTime+ is not aware of DST rules and so some of these methods have edge cases when a DST change is going on. For example +seconds_since_midnight+ might not return the real amount in such a day.
2658
2919
 
2659
- ...
2920
+ h4(#calculations-datetime). Calculations
2660
2921
 
2661
- h3. Extensions to +Process+
2922
+ The class +DateTime+ is a subclass of +Date+ so by loading +active_support/core_ext/date/calculations.rb+ you inherit these methods and their aliases, except that they will always return datetimes:
2923
+
2924
+ <ruby>
2925
+ yesterday
2926
+ tomorrow
2927
+ beginning_of_week
2928
+ end_on_week
2929
+ next_week
2930
+ months_ago
2931
+ months_since
2932
+ beginning_of_month
2933
+ end_of_month
2934
+ prev_month
2935
+ next_month
2936
+ beginning_of_quarter
2937
+ end_of_quarter
2938
+ beginning_of_year
2939
+ end_of_year
2940
+ years_ago
2941
+ years_since
2942
+ prev_year
2943
+ next_year
2944
+ </ruby>
2945
+
2946
+ The following methods are reimplemented so you do *not* need to load +active_support/core_ext/date/calculations.rb+ for these ones:
2947
+
2948
+ <ruby>
2949
+ beginning_of_day
2950
+ end_of_day
2951
+ ago
2952
+ since
2953
+ </ruby>
2954
+
2955
+ On the other hand, +advance+ and +change+ are also defined and support more options, they are documented below.
2956
+
2957
+ h5. Named Datetimes
2958
+
2959
+ h6. +DateTime.current+
2960
+
2961
+ Active Support defines +DateTime.current+ to be like +Time.now.to_datetime+, except that it honors the user time zone, if defined. It also defines instance predicates +past?+, and +future?+ relative to +DateTime.current+.
2962
+
2963
+ h5. Other Extensions
2964
+
2965
+ h6. +seconds_since_midnight+
2966
+
2967
+ The method +seconds_since_midnight+ returns the number of seconds since midnight:
2968
+
2969
+ <ruby>
2970
+ now = DateTime.current # => Mon, 07 Jun 2010 20:26:36 +0000
2971
+ now.seconds_since_midnight # => 73596
2972
+ </ruby>
2973
+
2974
+ h6(#utc-datetime). +utc+
2975
+
2976
+ The method +utc+ gives you the same datetime in the receiver expressed in UTC.
2977
+
2978
+ <ruby>
2979
+ now = DateTime.current # => Mon, 07 Jun 2010 19:27:52 -0400
2980
+ now.utc # => Mon, 07 Jun 2010 23:27:52 +0000
2981
+ </ruby>
2982
+
2983
+ This method is also aliased as +getutc+.
2984
+
2985
+ h6. +utc?+
2986
+
2987
+ The predicate +utc?+ says whether the receiver has UTC as its time zone:
2988
+
2989
+ <ruby>
2990
+ now = DateTime.now # => Mon, 07 Jun 2010 19:30:47 -0400
2991
+ now.utc? # => false
2992
+ now.utc.utc? # => true
2993
+ </ruby>
2994
+
2995
+ h5(#datetime-changing-components). Changing Components
2996
+
2997
+ The method +change+ allows you to get a new datetime which is the same as the receiver except for the given options, which may include +:year+, +:month+, +:day+, +:hour+, +:min+, +:sec+, +:offset+, +:start+:
2998
+
2999
+ <ruby>
3000
+ now = DateTime.current
3001
+ # => Tue, 08 Jun 2010 01:56:22 +0000
3002
+ now.change(:year => 2011, :offset => Rational(-6, 24))
3003
+ # => Wed, 08 Jun 2011 01:56:22 -0600
3004
+ </ruby>
3005
+
3006
+ If hours are zeroed, then minutes and seconds are too (unless they have given values):
3007
+
3008
+ <ruby>
3009
+ now.change(:hour => 0)
3010
+ # => Tue, 08 Jun 2010 00:00:00 +0000
3011
+ </ruby>
3012
+
3013
+ Similarly, if minutes are zeroed, then seconds are too (unless it has given a value):
3014
+
3015
+ <ruby>
3016
+ now.change(:min => 0)
3017
+ # => Tue, 08 Jun 2010 01:00:00 +0000
3018
+ </ruby>
3019
+
3020
+ This method is not tolerant to non-existing dates, if the change is invalid +ArgumentError+ is raised:
3021
+
3022
+ <ruby>
3023
+ DateTime.current.change(:month => 2, :day => 30)
3024
+ # => ArgumentError: invalid date
3025
+ </ruby>
3026
+
3027
+ h4(#datetime-conversions). Conversions
3028
+
3029
+ h3. Extensions to +Time+
2662
3030
 
2663
3031
  ...
2664
3032
 
2665
- h3. Extensions to +Pathname+
3033
+ h3. Extensions to +Process+
2666
3034
 
2667
3035
  ...
2668
3036