railties 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js +59 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js +75 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js +59 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js +65 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js +100 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js +97 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js +91 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js +55 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js +41 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js +52 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js +67 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js +52 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js +57 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js +58 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js +72 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js +88 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js +33 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js +74 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js +64 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js +55 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js +94 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js +51 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js +66 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js +56 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js +69 -0
- data/guides/assets/javascripts/syntaxhighlighter/shCore.js +17 -0
- data/guides/assets/stylesheets/main.css +6 -13
- data/guides/assets/stylesheets/syntaxhighlighter/shCore.css +226 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css +328 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css +331 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css +339 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css +328 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css +117 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css +120 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css +128 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css +117 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeRailsGuides.css +116 -0
- data/guides/rails_guides/generator.rb +21 -3
- data/guides/source/3_0_release_notes.textile +3 -7
- data/guides/source/action_controller_overview.textile +8 -1
- data/guides/source/action_mailer_basics.textile +1 -1
- data/guides/source/action_view_overview.textile +1 -1
- data/guides/source/active_record_querying.textile +44 -50
- data/guides/source/active_record_validations_callbacks.textile +3 -3
- data/guides/source/caching_with_rails.textile +1 -1
- data/guides/source/configuring.textile +3 -3
- data/guides/source/debugging_rails_applications.textile +6 -4
- data/guides/source/form_helpers.textile +21 -15
- data/guides/source/getting_started.textile +2 -12
- data/guides/source/i18n.textile +6 -0
- data/guides/source/index.html.erb +10 -2
- data/guides/source/layout.html.erb +13 -5
- data/guides/source/layouts_and_rendering.textile +2 -2
- data/guides/source/migrations.textile +1 -1
- data/guides/source/performance_testing.textile +6 -6
- data/guides/source/plugins.textile +9 -9
- data/guides/source/routing.textile +45 -25
- data/guides/source/ruby_on_rails_guides_guidelines.textile +77 -0
- data/lib/rails/application/configuration.rb +2 -0
- data/lib/rails/application/finisher.rb +7 -0
- data/lib/rails/code_statistics.rb +1 -1
- data/lib/rails/commands/console.rb +1 -1
- data/lib/rails/commands/runner.rb +2 -2
- data/lib/rails/engine/configuration.rb +6 -0
- data/lib/rails/generators/generated_attribute.rb +1 -0
- data/lib/rails/generators/rails/app/app_generator.rb +7 -4
- data/lib/rails/generators/rails/app/templates/Gemfile +2 -3
- data/lib/rails/generators/rails/app/templates/README +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +1 -1
- data/lib/rails/generators/resource_helpers.rb +1 -1
- data/lib/rails/plugin.rb +1 -1
- data/lib/rails/railtie.rb +1 -1
- data/lib/rails/railtie/configuration.rb +4 -3
- data/lib/rails/ruby_version_check.rb +1 -2
- data/lib/rails/tasks/misc.rake +1 -1
- data/lib/rails/version.rb +2 -2
- metadata +70 -15
- data/guides/assets/javascripts/code_highlighter.js +0 -188
- data/guides/assets/javascripts/highlighters.js +0 -90
- data/guides/assets/stylesheets/syntax.css +0 -31
@@ -0,0 +1,116 @@
|
|
1
|
+
/**
|
2
|
+
* Theme by fxn, took shThemeEclipse.css as starting point.
|
3
|
+
*/
|
4
|
+
.syntaxhighlighter {
|
5
|
+
background-color: #eee !important;
|
6
|
+
font-family: "Anonymous Pro", "Inconsolata", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace !important;
|
7
|
+
overflow-y: hidden !important;
|
8
|
+
overflow-x: auto !important;
|
9
|
+
}
|
10
|
+
.syntaxhighlighter .line.alt1 {
|
11
|
+
background-color: #eee !important;
|
12
|
+
}
|
13
|
+
.syntaxhighlighter .line.alt2 {
|
14
|
+
background-color: #eee !important;
|
15
|
+
}
|
16
|
+
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
|
17
|
+
background-color: #c3defe !important;
|
18
|
+
}
|
19
|
+
.syntaxhighlighter .line.highlighted.number {
|
20
|
+
color: #eee !important;
|
21
|
+
}
|
22
|
+
.syntaxhighlighter table caption {
|
23
|
+
color: #222 !important;
|
24
|
+
}
|
25
|
+
.syntaxhighlighter .gutter {
|
26
|
+
color: #787878 !important;
|
27
|
+
}
|
28
|
+
.syntaxhighlighter .gutter .line {
|
29
|
+
border-right: 3px solid #d4d0c8 !important;
|
30
|
+
}
|
31
|
+
.syntaxhighlighter .gutter .line.highlighted {
|
32
|
+
background-color: #d4d0c8 !important;
|
33
|
+
color: #eee !important;
|
34
|
+
}
|
35
|
+
.syntaxhighlighter.printing .line .content {
|
36
|
+
border: none !important;
|
37
|
+
}
|
38
|
+
.syntaxhighlighter.collapsed {
|
39
|
+
overflow: visible !important;
|
40
|
+
}
|
41
|
+
.syntaxhighlighter.collapsed .toolbar {
|
42
|
+
color: #3f5fbf !important;
|
43
|
+
background: #eee !important;
|
44
|
+
border: 1px solid #d4d0c8 !important;
|
45
|
+
}
|
46
|
+
.syntaxhighlighter.collapsed .toolbar a {
|
47
|
+
color: #3f5fbf !important;
|
48
|
+
}
|
49
|
+
.syntaxhighlighter.collapsed .toolbar a:hover {
|
50
|
+
color: #aa7700 !important;
|
51
|
+
}
|
52
|
+
.syntaxhighlighter .toolbar {
|
53
|
+
color: #a0a0a0 !important;
|
54
|
+
background: #d4d0c8 !important;
|
55
|
+
border: none !important;
|
56
|
+
}
|
57
|
+
.syntaxhighlighter .toolbar a {
|
58
|
+
color: #a0a0a0 !important;
|
59
|
+
}
|
60
|
+
.syntaxhighlighter .toolbar a:hover {
|
61
|
+
color: red !important;
|
62
|
+
}
|
63
|
+
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
|
64
|
+
color: #222 !important;
|
65
|
+
}
|
66
|
+
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
|
67
|
+
color: #708090 !important;
|
68
|
+
}
|
69
|
+
.syntaxhighlighter .string, .syntaxhighlighter .string a {
|
70
|
+
font-style: italic !important;
|
71
|
+
color: #6588A8 !important;
|
72
|
+
}
|
73
|
+
.syntaxhighlighter .keyword {
|
74
|
+
color: #64434d !important;
|
75
|
+
}
|
76
|
+
.syntaxhighlighter .preprocessor {
|
77
|
+
color: #646464 !important;
|
78
|
+
}
|
79
|
+
.syntaxhighlighter .variable {
|
80
|
+
color: #222 !important;
|
81
|
+
}
|
82
|
+
.syntaxhighlighter .value {
|
83
|
+
color: #009900 !important;
|
84
|
+
}
|
85
|
+
.syntaxhighlighter .functions {
|
86
|
+
color: #ff1493 !important;
|
87
|
+
}
|
88
|
+
.syntaxhighlighter .constants {
|
89
|
+
color: #0066cc !important;
|
90
|
+
}
|
91
|
+
.syntaxhighlighter .script {
|
92
|
+
color: #222 !important;
|
93
|
+
background-color: none !important;
|
94
|
+
}
|
95
|
+
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
|
96
|
+
color: gray !important;
|
97
|
+
}
|
98
|
+
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
|
99
|
+
color: #222 !important;
|
100
|
+
font-weight: bold !important;
|
101
|
+
}
|
102
|
+
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
|
103
|
+
color: red !important;
|
104
|
+
}
|
105
|
+
|
106
|
+
.syntaxhighlighter .xml .keyword {
|
107
|
+
color: #64434d !important;
|
108
|
+
font-weight: normal !important;
|
109
|
+
}
|
110
|
+
.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a {
|
111
|
+
color: #7f007f !important;
|
112
|
+
}
|
113
|
+
.syntaxhighlighter .xml .string {
|
114
|
+
font-style: italic !important;
|
115
|
+
color: #6588A8 !important;
|
116
|
+
}
|
@@ -207,10 +207,28 @@ module RailsGuides
|
|
207
207
|
# with code blocks by hand.
|
208
208
|
def with_workaround_for_notextile(body)
|
209
209
|
code_blocks = []
|
210
|
+
|
210
211
|
body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)</\1>}m) do |m|
|
211
|
-
|
212
|
-
|
213
|
-
|
212
|
+
brush = case $1
|
213
|
+
when 'ruby', 'sql', 'plain'
|
214
|
+
$1
|
215
|
+
when 'erb'
|
216
|
+
'ruby; html-script: true'
|
217
|
+
when 'html'
|
218
|
+
'xml' # html is understood, but there are .xml rules in the CSS
|
219
|
+
else
|
220
|
+
'plain'
|
221
|
+
end
|
222
|
+
|
223
|
+
code_blocks.push(<<HTML)
|
224
|
+
<notextile>
|
225
|
+
<div class="code_container">
|
226
|
+
<pre class="brush: #{brush}; gutter: false; toolbar: false">
|
227
|
+
#{ERB::Util.h($2).strip}
|
228
|
+
</pre>
|
229
|
+
</div>
|
230
|
+
</notextile>
|
231
|
+
HTML
|
214
232
|
"\ndirty_workaround_for_notextile_#{code_blocks.size - 1}\n"
|
215
233
|
end
|
216
234
|
|
@@ -18,13 +18,11 @@ These release notes cover the major upgrades, but don't include every little bug
|
|
18
18
|
|
19
19
|
endprologue.
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
To install the last Rails 3 beta:
|
21
|
+
To install Rails 3:
|
24
22
|
|
25
23
|
<shell>
|
26
24
|
# Use sudo if your setup requires it
|
27
|
-
gem install rails
|
25
|
+
gem install rails
|
28
26
|
</shell>
|
29
27
|
|
30
28
|
|
@@ -77,10 +75,8 @@ More information - "The Path to Rails 3: Approaching the upgrade":http://omgblog
|
|
77
75
|
|
78
76
|
h3. Creating a Rails 3.0 application
|
79
77
|
|
80
|
-
The new installing rails sequence (for the beta) is:
|
81
|
-
|
82
78
|
<shell>
|
83
|
-
|
79
|
+
# You should have the 'rails' rubygem installed
|
84
80
|
$ rails new myapp
|
85
81
|
$ cd myapp
|
86
82
|
</shell>
|
@@ -242,7 +242,7 @@ class LoginsController < ApplicationController
|
|
242
242
|
# "Delete" a login, aka "log the user out"
|
243
243
|
def destroy
|
244
244
|
# Remove the user id from the session
|
245
|
-
session[:current_user_id] = nil
|
245
|
+
@_current_user = session[:current_user_id] = nil
|
246
246
|
redirect_to root_url
|
247
247
|
end
|
248
248
|
end
|
@@ -264,6 +264,13 @@ class LoginsController < ApplicationController
|
|
264
264
|
end
|
265
265
|
</ruby>
|
266
266
|
|
267
|
+
Note it is also possible to assign a flash message as part of the redirection.
|
268
|
+
|
269
|
+
<ruby>
|
270
|
+
redirect_to root_url, :notice => "You have successfully logged out"
|
271
|
+
</ruby>
|
272
|
+
|
273
|
+
|
267
274
|
The +destroy+ action redirects to the application's +root_url+, where the message will be displayed. Note that it's entirely up to the next action to decide what, if anything, it will do with what the previous action put in the flash. It's conventional to display eventual errors or notices from the flash in the application's layout:
|
268
275
|
|
269
276
|
<ruby>
|
@@ -462,7 +462,7 @@ class UserMailerTest < ActionMailer::TestCase
|
|
462
462
|
user = users(:some_user_in_your_fixtures)
|
463
463
|
|
464
464
|
# Send the email, then test that it got queued
|
465
|
-
email = UserMailer.
|
465
|
+
email = UserMailer.welcome_email(user).deliver
|
466
466
|
assert !ActionMailer::Base.deliveries.empty?
|
467
467
|
|
468
468
|
# Test the body of the sent email contains what we expect it to
|
@@ -233,7 +233,7 @@ h4. AssetTagHelper
|
|
233
233
|
|
234
234
|
This module provides methods for generating HTML that links views to assets such as images, javascripts, stylesheets, and feeds.
|
235
235
|
|
236
|
-
By default, Rails links to these assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated assets server by setting +ActionController::Base.asset_host+ in
|
236
|
+
By default, Rails links to these assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated assets server by setting +ActionController::Base.asset_host+ in the application configuration, typically in +config/environments/production.rb+. For example, let's say your asset host is +assets.example.com+:
|
237
237
|
|
238
238
|
<ruby>
|
239
239
|
ActionController::Base.asset_host = "assets.example.com"
|
@@ -159,14 +159,14 @@ The following may seem very straight forward at first:
|
|
159
159
|
|
160
160
|
<ruby>
|
161
161
|
# Very inefficient when users table has thousands of rows.
|
162
|
-
User.each do |user|
|
162
|
+
User.all.each do |user|
|
163
163
|
NewsLetter.weekly_deliver(user)
|
164
164
|
end
|
165
165
|
</ruby>
|
166
166
|
|
167
167
|
But if the total number of rows in the table is very large, the above approach may vary from being under performant to just plain impossible.
|
168
168
|
|
169
|
-
This is because +User.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory.
|
169
|
+
This is because +User.all.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory.
|
170
170
|
|
171
171
|
h5. +find_each+
|
172
172
|
|
@@ -234,7 +234,7 @@ h4. Array Conditions
|
|
234
234
|
Now what if that number could vary, say as an argument from somewhere, or perhaps from the user's level status somewhere? The find then becomes something like:
|
235
235
|
|
236
236
|
<ruby>
|
237
|
-
Client.where(
|
237
|
+
Client.where("orders_count = ?", params[:orders])
|
238
238
|
</ruby>
|
239
239
|
|
240
240
|
Active Record will go through the first element in the conditions value and any additional elements will replace the question marks +(?)+ in the first element.
|
@@ -242,7 +242,7 @@ Active Record will go through the first element in the conditions value and any
|
|
242
242
|
Or if you want to specify two conditions, you can do it like:
|
243
243
|
|
244
244
|
<ruby>
|
245
|
-
Client.where(
|
245
|
+
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
|
246
246
|
</ruby>
|
247
247
|
|
248
248
|
In this example, the first question mark will be replaced with the value in +params[:orders]+ and the second will be replaced with the SQL representation of +false+, which depends on the adapter.
|
@@ -250,7 +250,7 @@ In this example, the first question mark will be replaced with the value in +par
|
|
250
250
|
The reason for doing code like:
|
251
251
|
|
252
252
|
<ruby>
|
253
|
-
Client.where(
|
253
|
+
Client.where("orders_count = ?", params[:orders])
|
254
254
|
</ruby>
|
255
255
|
|
256
256
|
instead of:
|
@@ -268,8 +268,8 @@ h5. Placeholder Conditions
|
|
268
268
|
Similar to the +(?)+ replacement style of params, you can also specify keys/values hash in your array conditions:
|
269
269
|
|
270
270
|
<ruby>
|
271
|
-
Client.where(
|
272
|
-
|
271
|
+
Client.where("created_at >= :start_date AND created_at <= :end_date",
|
272
|
+
{:start_date => params[:start_date], :end_date => params[:end_date]})
|
273
273
|
</ruby>
|
274
274
|
|
275
275
|
This makes for clearer readability if you have a large number of variable conditions.
|
@@ -279,8 +279,8 @@ h5(#array-range_conditions). Range Conditions
|
|
279
279
|
If you're looking for a range inside of a table (for example, users created in a certain timeframe) you can use the conditions option coupled with the +IN+ SQL statement for this. If you had two dates coming in from a controller you could do something like this to look for a range:
|
280
280
|
|
281
281
|
<ruby>
|
282
|
-
Client.where(
|
283
|
-
(params[:start_date].to_date)..(params[:end_date].to_date)
|
282
|
+
Client.where("created_at IN (?)",
|
283
|
+
(params[:start_date].to_date)..(params[:end_date].to_date))
|
284
284
|
</ruby>
|
285
285
|
|
286
286
|
This would generate the proper query which is great for small ranges but not so good for larger ranges. For example if you pass in a range of date objects spanning a year that's 365 (or possibly 366, depending on the year) strings it will attempt to match your field against.
|
@@ -301,8 +301,8 @@ h5. Time and Date Conditions
|
|
301
301
|
Things can get *really* messy if you pass in Time objects as it will attempt to compare your field to *every second* in that range:
|
302
302
|
|
303
303
|
<ruby>
|
304
|
-
Client.where(
|
305
|
-
(params[:start_date].to_date.to_time)..(params[:end_date].to_date.to_time)
|
304
|
+
Client.where("created_at IN (?)",
|
305
|
+
(params[:start_date].to_date.to_time)..(params[:end_date].to_date.to_time))
|
306
306
|
</ruby>
|
307
307
|
|
308
308
|
<sql>
|
@@ -323,14 +323,14 @@ In this example it would be better to use greater-than and less-than operators i
|
|
323
323
|
|
324
324
|
<ruby>
|
325
325
|
Client.where(
|
326
|
-
|
326
|
+
"created_at > ? AND created_at < ?", params[:start_date], params[:end_date])
|
327
327
|
</ruby>
|
328
328
|
|
329
329
|
You can also use the greater-than-or-equal-to and less-than-or-equal-to like this:
|
330
330
|
|
331
331
|
<ruby>
|
332
332
|
Client.where(
|
333
|
-
|
333
|
+
"created_at >= ? AND created_at <= ?", params[:start_date], params[:end_date])
|
334
334
|
</ruby>
|
335
335
|
|
336
336
|
Just like in Ruby. If you want a shorter syntax be sure to check out the "Hash Conditions":#hash-conditions section later on in the guide.
|
@@ -344,13 +344,13 @@ NOTE: Only equality, range and subset checking are possible with Hash conditions
|
|
344
344
|
h5. Equality Conditions
|
345
345
|
|
346
346
|
<ruby>
|
347
|
-
Client.where(
|
347
|
+
Client.where(:locked => true)
|
348
348
|
</ruby>
|
349
349
|
|
350
350
|
The field name can also be a string:
|
351
351
|
|
352
352
|
<ruby>
|
353
|
-
Client.where(
|
353
|
+
Client.where('locked' => true)
|
354
354
|
</ruby>
|
355
355
|
|
356
356
|
h5(#hash-range_conditions). Range Conditions
|
@@ -358,7 +358,7 @@ h5(#hash-range_conditions). Range Conditions
|
|
358
358
|
The good thing about this is that we can pass in a range for our fields without it generating a large query as shown in the preamble of this section.
|
359
359
|
|
360
360
|
<ruby>
|
361
|
-
Client.where(
|
361
|
+
Client.where(:created_at => (Time.now.midnight - 1.day)..Time.now.midnight)
|
362
362
|
</ruby>
|
363
363
|
|
364
364
|
This will find all clients created yesterday by using a +BETWEEN+ SQL statement:
|
@@ -374,7 +374,7 @@ h5. Subset Conditions
|
|
374
374
|
If you want to find records using the +IN+ expression you can pass an array to the conditions hash:
|
375
375
|
|
376
376
|
<ruby>
|
377
|
-
Client.where(
|
377
|
+
Client.where(:orders_count => [1,3,5])
|
378
378
|
</ruby>
|
379
379
|
|
380
380
|
This code will generate SQL like this:
|
@@ -496,7 +496,7 @@ SQL uses the +HAVING+ clause to specify conditions on the +GROUP BY+ fields. You
|
|
496
496
|
For example:
|
497
497
|
|
498
498
|
<ruby>
|
499
|
-
Order.group("date(created_at)".having(
|
499
|
+
Order.group("date(created_at)".having("created_at > ?", 1.month.ago)
|
500
500
|
</ruby>
|
501
501
|
|
502
502
|
The SQL that would be executed would be something like this:
|
@@ -509,22 +509,16 @@ This will return single order objects for each day, but only for the last month.
|
|
509
509
|
|
510
510
|
h4. Readonly Objects
|
511
511
|
|
512
|
-
|
513
|
-
|
514
|
-
Any attempt to alter or destroy the readonly records will not succeed, raising an +ActiveRecord::ReadOnlyRecord+ exception. To set this option, specify it like this:
|
512
|
+
Active Record provides +readonly+ method on a relation to explicitly disallow modification or deletion of any of the returned object. Any attempt to alter or destroy a readonly record will not succeed, raising an +ActiveRecord::ReadOnlyRecord+ exception.
|
515
513
|
|
516
514
|
<ruby>
|
517
|
-
Client.first
|
518
|
-
|
519
|
-
|
520
|
-
For example, calling the following code will raise an +ActiveRecord::ReadOnlyRecord+ exception:
|
521
|
-
|
522
|
-
<ruby>
|
523
|
-
client = Client.first.readonly(true)
|
524
|
-
client.locked = false
|
515
|
+
client = Client.readonly.first
|
516
|
+
client.visits += 1
|
525
517
|
client.save
|
526
518
|
</ruby>
|
527
519
|
|
520
|
+
As +client+ is explicitly set to be a readonly object, the above code will raise an +ActiveRecord::ReadOnlyRecord+ exception when calling +client.save+ with an updated value of _visists_.
|
521
|
+
|
528
522
|
h4. Locking Records for Update
|
529
523
|
|
530
524
|
Locking is helpful for preventing race conditions when updating records in the database and ensuring atomic updates.
|
@@ -571,13 +565,13 @@ end
|
|
571
565
|
|
572
566
|
h5. Pessimistic Locking
|
573
567
|
|
574
|
-
Pessimistic locking uses a locking mechanism provided by the underlying database.
|
568
|
+
Pessimistic locking uses a locking mechanism provided by the underlying database. Using +lock+ when building a relation obtains an exclusive lock on the selected rows. Relations using +lock+ are usually wrapped inside a transaction for preventing deadlock conditions.
|
575
569
|
|
576
570
|
For example:
|
577
571
|
|
578
572
|
<ruby>
|
579
573
|
Item.transaction do
|
580
|
-
i = Item.first
|
574
|
+
i = Item.lock.first
|
581
575
|
i.name = 'Jones'
|
582
576
|
i.save
|
583
577
|
end
|
@@ -592,25 +586,25 @@ Item Update (0.4ms) UPDATE `items` SET `updated_at` = '2009-02-07 18:05:56', `
|
|
592
586
|
SQL (0.8ms) COMMIT
|
593
587
|
</sql>
|
594
588
|
|
595
|
-
You can also pass raw SQL to the
|
589
|
+
You can also pass raw SQL to the +lock+ method for allowing different types of locks. For example, MySQL has an expression called +LOCK IN SHARE MODE+ where you can lock a record but still allow other queries to read it. To specify this expression just pass it in as the lock option:
|
596
590
|
|
597
591
|
<ruby>
|
598
592
|
Item.transaction do
|
599
|
-
i = Item.
|
593
|
+
i = Item.lock("LOCK IN SHARE MODE").find(1)
|
600
594
|
i.increment!(:views)
|
601
595
|
end
|
602
596
|
</ruby>
|
603
597
|
|
604
598
|
h3. Joining Tables
|
605
599
|
|
606
|
-
|
600
|
+
Active Record provides a finder method called +joins+ for specifying +JOIN+ clauses on the resulting SQL. There are multiple ways to use the +joins+ method.
|
607
601
|
|
608
602
|
h4. Using a String SQL Fragment
|
609
603
|
|
610
|
-
You can just supply the raw SQL specifying the +JOIN+ clause to
|
604
|
+
You can just supply the raw SQL specifying the +JOIN+ clause to +joins+:
|
611
605
|
|
612
606
|
<ruby>
|
613
|
-
Client.
|
607
|
+
Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
|
614
608
|
</ruby>
|
615
609
|
|
616
610
|
This will result in the following SQL:
|
@@ -625,7 +619,7 @@ WARNING: This method only works with +INNER JOIN+,
|
|
625
619
|
|
626
620
|
<br />
|
627
621
|
|
628
|
-
Active Record lets you use the names of the "associations":association_basics.html defined on the model as a shortcut for specifying the
|
622
|
+
Active Record lets you use the names of the "associations":association_basics.html defined on the model as a shortcut for specifying +JOIN+ clause for those associations when using the +joins+ method.
|
629
623
|
|
630
624
|
For example, consider the following +Category+, +Post+, +Comments+ and +Guest+ models:
|
631
625
|
|
@@ -838,13 +832,13 @@ Client.exists?(1,2,3)
|
|
838
832
|
Client.exists?([1,2,3])
|
839
833
|
</ruby>
|
840
834
|
|
841
|
-
|
835
|
+
It's even possible to use +exists?+ without any arguments on a model or a relation.
|
842
836
|
|
843
837
|
<ruby>
|
844
|
-
Client.
|
838
|
+
Client.where(:first_name => 'Ryan').exists?
|
845
839
|
</ruby>
|
846
840
|
|
847
|
-
|
841
|
+
The above returns +true+ if there is at least one client with the +first_name+ 'Ryan' and +false+ otherwise.
|
848
842
|
|
849
843
|
<ruby>
|
850
844
|
Client.exists?
|
@@ -856,22 +850,24 @@ h3. Calculations
|
|
856
850
|
|
857
851
|
This section uses count as an example method in this preamble, but the options described apply to all sub-sections.
|
858
852
|
|
859
|
-
|
853
|
+
All calculation methods work directly on a model:
|
860
854
|
|
861
855
|
<ruby>
|
862
|
-
Client.count
|
856
|
+
Client.count
|
857
|
+
# SELECT count(*) AS count_all FROM clients
|
863
858
|
</ruby>
|
864
859
|
|
865
|
-
|
860
|
+
Or on a relation :
|
866
861
|
|
867
|
-
<
|
868
|
-
|
869
|
-
|
862
|
+
<ruby>
|
863
|
+
Client.where(:first_name => 'Ryan').count
|
864
|
+
# SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
|
865
|
+
</ruby>
|
870
866
|
|
871
|
-
You can also use
|
867
|
+
You can also use various finder methods on a relation for performing complex calculations:
|
872
868
|
|
873
869
|
<ruby>
|
874
|
-
Client.
|
870
|
+
Client.includes("orders").where(:first_name => 'Ryan', :orders => {:status => 'received'}).count
|
875
871
|
</ruby>
|
876
872
|
|
877
873
|
Which will execute:
|
@@ -882,8 +878,6 @@ SELECT count(DISTINCT clients.id) AS count_all FROM clients
|
|
882
878
|
(clients.first_name = 'Ryan' AND orders.status = 'received')
|
883
879
|
</sql>
|
884
880
|
|
885
|
-
This code specifies +clients.first_name+ just in case one of the join tables has a field also called +first_name+ and it uses +orders.status+ because that's the name of our join table.
|
886
|
-
|
887
881
|
h4. Count
|
888
882
|
|
889
883
|
If you want to see how many records are in your model's table you could call +Client.count+ and that will return the number. If you want to be more specific and find all the clients with their age present in the database you can use +Client.count(:age)+.
|