railties 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +36 -49
- data/README.rdoc +2 -1
- data/guides/assets/stylesheets/fixes.css +16 -0
- data/guides/rails_guides.rb +2 -2
- data/guides/rails_guides/generator.rb +8 -3
- data/guides/rails_guides/textile_extensions.rb +4 -2
- data/guides/source/2_2_release_notes.textile +3 -3
- data/guides/source/2_3_release_notes.textile +2 -2
- data/guides/source/3_0_release_notes.textile +14 -14
- data/guides/source/action_controller_overview.textile +54 -79
- data/guides/source/action_mailer_basics.textile +39 -9
- data/guides/source/action_view_overview.textile +257 -211
- data/guides/source/active_record_basics.textile +1 -1
- data/guides/source/active_record_querying.textile +217 -27
- data/guides/source/active_record_validations_callbacks.textile +94 -25
- data/guides/source/active_support_core_extensions.textile +109 -77
- data/guides/source/ajax_on_rails.textile +15 -150
- data/guides/source/api_documentation_guidelines.textile +12 -12
- data/guides/source/association_basics.textile +74 -60
- data/guides/source/caching_with_rails.textile +59 -60
- data/guides/source/command_line.textile +46 -47
- data/guides/source/configuring.textile +55 -37
- data/guides/source/contribute.textile +7 -7
- data/guides/source/contributing_to_ruby_on_rails.textile +14 -23
- data/guides/source/credits.html.erb +3 -3
- data/guides/source/debugging_rails_applications.textile +59 -46
- data/guides/source/form_helpers.textile +76 -31
- data/guides/source/generators.textile +39 -40
- data/guides/source/getting_started.textile +73 -94
- data/guides/source/i18n.textile +64 -58
- data/guides/source/index.html.erb +3 -3
- data/guides/source/initialization.textile +634 -3284
- data/guides/source/layout.html.erb +6 -7
- data/guides/source/layouts_and_rendering.textile +59 -60
- data/guides/source/migrations.textile +63 -59
- data/guides/source/nested_model_forms.textile +2 -2
- data/guides/source/performance_testing.textile +16 -16
- data/guides/source/plugins.textile +236 -1280
- data/guides/source/rails_application_templates.textile +37 -29
- data/guides/source/rails_on_rack.textile +4 -9
- data/guides/source/routing.textile +96 -75
- data/guides/source/ruby_on_rails_guides_guidelines.textile +19 -12
- data/guides/source/security.textile +57 -30
- data/guides/source/testing.textile +26 -24
- data/guides/w3c_validator.rb +2 -2
- data/lib/rails.rb +1 -7
- data/lib/rails/application.rb +46 -76
- data/lib/rails/application/bootstrap.rb +6 -11
- data/lib/rails/application/configuration.rb +43 -40
- data/lib/rails/application/finisher.rb +16 -4
- data/lib/rails/application/railties.rb +6 -24
- data/lib/rails/application/routes_reloader.rb +45 -0
- data/lib/rails/backtrace_cleaner.rb +1 -1
- data/lib/rails/cli.rb +7 -5
- data/lib/rails/commands.rb +27 -2
- data/lib/rails/commands/application.rb +14 -1
- data/lib/rails/commands/benchmarker.rb +3 -1
- data/lib/rails/commands/dbconsole.rb +2 -2
- data/lib/rails/commands/destroy.rb +3 -1
- data/lib/rails/commands/generate.rb +3 -1
- data/lib/rails/commands/plugin.rb +2 -7
- data/lib/rails/commands/plugin_new.rb +10 -0
- data/lib/rails/commands/profiler.rb +3 -1
- data/lib/rails/commands/server.rb +4 -0
- data/lib/rails/configuration.rb +8 -81
- data/lib/rails/console/app.rb +2 -2
- data/lib/rails/engine.rb +460 -78
- data/lib/rails/engine/configuration.rb +46 -49
- data/lib/rails/engine/railties.rb +33 -0
- data/lib/rails/generators.rb +11 -5
- data/lib/rails/generators/actions.rb +2 -27
- data/lib/rails/generators/app_base.rb +216 -0
- data/lib/rails/generators/base.rb +3 -2
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +1 -1
- data/lib/rails/generators/generated_attribute.rb +2 -1
- data/lib/rails/generators/migration.rb +6 -2
- data/lib/rails/generators/named_base.rb +79 -3
- data/lib/rails/generators/rails/app/app_generator.rb +44 -209
- data/lib/rails/generators/rails/app/templates/Gemfile +15 -31
- data/lib/rails/generators/rails/app/templates/README +2 -2
- data/lib/rails/generators/rails/app/templates/Rakefile +1 -1
- data/lib/rails/generators/rails/app/templates/{public → app/assets}/images/rails.png +0 -0
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +8 -0
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +5 -0
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +4 -4
- data/lib/rails/generators/rails/app/templates/config/application.rb +19 -3
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +4 -4
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +11 -6
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +1 -2
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +14 -11
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +12 -0
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/routes.rb +1 -1
- data/lib/rails/generators/rails/app/templates/db/{seeds.rb → seeds.rb.tt} +2 -2
- data/lib/rails/generators/rails/app/templates/public/index.html +10 -8
- data/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/{test_helper.rb.tt → test_helper.rb} +0 -0
- data/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/rails/generators/rails/assets/USAGE +20 -0
- data/lib/rails/generators/rails/assets/assets_generator.rb +39 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js +2 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js.coffee +3 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css +4 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css.scss +5 -0
- data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
- data/lib/rails/generators/rails/controller/templates/controller.rb +2 -0
- data/lib/rails/generators/rails/generator/generator_generator.rb +2 -2
- data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/rails/generators/rails/helper/templates/helper.rb +2 -0
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -0
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +4 -4
- data/lib/rails/generators/rails/plugin_new/USAGE +10 -0
- data/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +303 -0
- data/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +9 -0
- data/lib/rails/generators/rails/plugin_new/templates/Gemfile +11 -0
- data/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE +20 -0
- data/lib/rails/generators/rails/plugin_new/templates/README.rdoc +3 -0
- data/lib/rails/generators/rails/plugin_new/templates/Rakefile +21 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/config/routes.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/gitignore +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +16 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +10 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +5 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +12 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +10 -0
- data/lib/rails/generators/rails/resource/resource_generator.rb +2 -2
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +20 -1
- data/lib/rails/generators/rails/{stylesheets → scaffold}/templates/scaffold.css +0 -0
- data/lib/rails/generators/rails/scaffold/templates/scaffold.css.scss +58 -0
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +21 -19
- data/lib/rails/generators/resource_helpers.rb +3 -3
- data/lib/rails/generators/test_case.rb +2 -20
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/helper/templates/helper_test.rb +2 -0
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +3 -4
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml +1 -1
- data/lib/rails/generators/test_unit/model/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/observer/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +3 -4
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +7 -5
- data/lib/rails/info.rb +0 -1
- data/lib/rails/paths.rb +119 -65
- data/lib/rails/plugin.rb +18 -19
- data/lib/rails/rack/log_tailer.rb +1 -1
- data/lib/rails/railtie.rb +50 -47
- data/lib/rails/railtie/configurable.rb +20 -10
- data/lib/rails/railtie/configuration.rb +20 -19
- data/lib/rails/source_annotation_extractor.rb +5 -5
- data/lib/rails/tasks.rb +1 -0
- data/lib/rails/tasks/assets.rake +10 -0
- data/lib/rails/tasks/documentation.rake +2 -8
- data/lib/rails/tasks/engine.rake +69 -0
- data/lib/rails/tasks/framework.rake +4 -21
- data/lib/rails/tasks/misc.rake +1 -1
- data/lib/rails/tasks/routes.rake +2 -1
- data/lib/rails/test_help.rb +17 -1
- data/lib/rails/test_unit/railtie.rb +1 -1
- data/lib/rails/test_unit/testing.rake +8 -3
- data/lib/rails/version.rb +3 -3
- metadata +128 -100
- checksums.yaml +0 -7
- data/lib/rails/application/configurable.rb +0 -19
- data/lib/rails/console/sandbox.rb +0 -6
- data/lib/rails/deprecation.rb +0 -41
- data/lib/rails/engine/configurable.rb +0 -25
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +0 -62
- data/lib/rails/generators/rails/app/templates/public/javascripts/application.js +0 -2
- data/lib/rails/generators/rails/app/templates/public/javascripts/controls.js +0 -965
- data/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js +0 -974
- data/lib/rails/generators/rails/app/templates/public/javascripts/effects.js +0 -1123
- data/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js +0 -6001
- data/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +0 -202
- data/lib/rails/generators/rails/stylesheets/USAGE +0 -5
- data/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb +0 -9
- data/lib/rails/info_routes.rb +0 -3
@@ -20,7 +20,7 @@ Thus, after a simple require like:
|
|
20
20
|
require 'active_support'
|
21
21
|
</ruby>
|
22
22
|
|
23
|
-
objects do not even respond to +blank
|
23
|
+
objects do not even respond to +blank?+. Let's see how to load its definition.
|
24
24
|
|
25
25
|
h5. Cherry-picking a Definition
|
26
26
|
|
@@ -42,7 +42,7 @@ h5. Loading Grouped Core Extensions
|
|
42
42
|
|
43
43
|
The next level is to simply load all extensions to +Object+. As a rule of thumb, extensions to +SomeClass+ are available in one shot by loading +active_support/core_ext/some_class+.
|
44
44
|
|
45
|
-
Thus,
|
45
|
+
Thus, to load all extensions to +Object+ (including +blank?+):
|
46
46
|
|
47
47
|
<ruby>
|
48
48
|
require 'active_support/core_ext/object'
|
@@ -167,6 +167,12 @@ def log_info(sql, name, ms)
|
|
167
167
|
end
|
168
168
|
</ruby>
|
169
169
|
|
170
|
+
+try+ can also be called without arguments but a block, which will only be executed if the object is not nil:
|
171
|
+
|
172
|
+
<ruby>
|
173
|
+
@person.try { |p| "#{p.first_name} #{p.last_name}" }
|
174
|
+
</ruby>
|
175
|
+
|
170
176
|
NOTE: Defined in +active_support/core_ext/object/try.rb+.
|
171
177
|
|
172
178
|
h4. +singleton_class+
|
@@ -395,39 +401,6 @@ C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
|
|
395
401
|
|
396
402
|
NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+.
|
397
403
|
|
398
|
-
h5. +copy_instance_variables_from(object, exclude = [])+
|
399
|
-
|
400
|
-
Copies the instance variables of +object+ into +self+.
|
401
|
-
|
402
|
-
Instance variable names in the +exclude+ array are ignored. If +object+
|
403
|
-
responds to +protected_instance_variables+ the ones returned are
|
404
|
-
also ignored. For example, Rails controllers implement that method.
|
405
|
-
|
406
|
-
In both arrays strings and symbols are understood, and they have to include
|
407
|
-
the at sign.
|
408
|
-
|
409
|
-
<ruby>
|
410
|
-
class C
|
411
|
-
def initialize(x, y, z)
|
412
|
-
@x, @y, @z = x, y, z
|
413
|
-
end
|
414
|
-
|
415
|
-
def protected_instance_variables
|
416
|
-
%w(@z)
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
a = C.new(0, 1, 2)
|
421
|
-
b = C.new(3, 4, 5)
|
422
|
-
|
423
|
-
a.copy_instance_variables_from(b, [:@y])
|
424
|
-
# a is now: @x = 3, @y = 1, @z = 2
|
425
|
-
</ruby>
|
426
|
-
|
427
|
-
In the example +object+ and +self+ are of the same type, but they don't need to.
|
428
|
-
|
429
|
-
NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+.
|
430
|
-
|
431
404
|
h4. Silencing Warnings, Streams, and Exceptions
|
432
405
|
|
433
406
|
The methods +silence_warnings+ and +enable_warnings+ change the value of +$VERBOSE+ accordingly for the duration of their block, and reset it afterwards:
|
@@ -459,7 +432,7 @@ h4. +require_library_or_gem+
|
|
459
432
|
|
460
433
|
The convenience method +require_library_or_gem+ tries to load its argument with a regular +require+ first. If it fails loads +rubygems+ and tries again.
|
461
434
|
|
462
|
-
If the first attempt is a failure and +rubygems+ can't be loaded the method raises +LoadError+.
|
435
|
+
If the first attempt is a failure and +rubygems+ can't be loaded the method raises +LoadError+. A +LoadError+ is also raised if +rubygems+ is available but the argument is not loadable as a gem.
|
463
436
|
|
464
437
|
For example, that's the way the MySQL adapter loads the MySQL library:
|
465
438
|
|
@@ -469,6 +442,20 @@ require_library_or_gem('mysql')
|
|
469
442
|
|
470
443
|
NOTE: Defined in +active_support/core_ext/kernel/requires.rb+.
|
471
444
|
|
445
|
+
h4. +in?+
|
446
|
+
|
447
|
+
The predicate +in?+ tests if an object is included in another object. An +ArgumentError+ exception will be raised if the argument passed does not respond to +include?+.
|
448
|
+
|
449
|
+
Examples of +in?+:
|
450
|
+
|
451
|
+
<ruby>
|
452
|
+
1.in?([1,2]) # => true
|
453
|
+
"lo".in?("hello") # => true
|
454
|
+
25.in?(30..50) # => false
|
455
|
+
</ruby>
|
456
|
+
|
457
|
+
NOTE: Defined in +active_support/core_ext/object/inclusion.rb+.
|
458
|
+
|
472
459
|
h3. Extensions to +Module+
|
473
460
|
|
474
461
|
h4. +alias_method_chain+
|
@@ -525,12 +512,12 @@ h4. Attributes
|
|
525
512
|
|
526
513
|
h5. +alias_attribute+
|
527
514
|
|
528
|
-
Model attributes have a reader, a writer, and a predicate. You can
|
515
|
+
Model attributes have a reader, a writer, and a predicate. You can alias a model attribute having the corresponding three methods defined for you in one shot. As in other aliasing methods, the new name is the first argument, and the old name is the second (my mnemonic is they go in the same order as if you did an assignment):
|
529
516
|
|
530
517
|
<ruby>
|
531
518
|
class User < ActiveRecord::Base
|
532
519
|
# let me refer to the email column as "login",
|
533
|
-
#
|
520
|
+
# possibly meaningful for authentication code
|
534
521
|
alias_attribute :login, :email
|
535
522
|
end
|
536
523
|
</ruby>
|
@@ -554,9 +541,9 @@ The default value can be also specified with a block, which is called in the con
|
|
554
541
|
<ruby>
|
555
542
|
class User
|
556
543
|
attr_accessor :name, :surname
|
557
|
-
attr_accessor_with_default(:full_name)
|
558
|
-
|
559
|
-
|
544
|
+
attr_accessor_with_default(:full_name) do
|
545
|
+
[name, surname].compact.join(" ")
|
546
|
+
end
|
560
547
|
end
|
561
548
|
|
562
549
|
u = User.new
|
@@ -590,7 +577,7 @@ h5. Internal Attributes
|
|
590
577
|
|
591
578
|
When you are defining an attribute in a class that is meant to be subclassed name collisions are a risk. That's remarkably important for libraries.
|
592
579
|
|
593
|
-
Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby
|
580
|
+
Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby built-in +attr_*+ counterparts, except they name the underlying instance variable in a way that makes collisions less likely.
|
594
581
|
|
595
582
|
The macro +attr_internal+ is a synonym for +attr_internal_accessor+:
|
596
583
|
|
@@ -1018,7 +1005,7 @@ a2.x # => 2, overridden in a2
|
|
1018
1005
|
The generation of the writer instance method can be prevented by setting the option +:instance_writer+ to false, as in
|
1019
1006
|
|
1020
1007
|
<ruby>
|
1021
|
-
module
|
1008
|
+
module ActiveRecord
|
1022
1009
|
class Base
|
1023
1010
|
class_attribute :table_name_prefix, :instance_writer => false
|
1024
1011
|
self.table_name_prefix = ""
|
@@ -1028,7 +1015,7 @@ end
|
|
1028
1015
|
|
1029
1016
|
A model may find that option useful as a way to prevent mass-assignment from setting the attribute.
|
1030
1017
|
|
1031
|
-
For convenience +class_attribute+ defines
|
1018
|
+
For convenience +class_attribute+ also defines an instance predicate which is the double negation of what the instance reader returns. In the examples above it would be called +x?+.
|
1032
1019
|
|
1033
1020
|
NOTE: Defined in +active_support/core_ext/class/attribute.rb+
|
1034
1021
|
|
@@ -1072,6 +1059,8 @@ NOTE: Defined in +active_support/core_ext/class/attribute_accessors.rb+.
|
|
1072
1059
|
|
1073
1060
|
h4. Class Inheritable Attributes
|
1074
1061
|
|
1062
|
+
WARNING: Class Inheritable Attributes are deprecated. It's recommended that you use +Class#class_attribute+ instead.
|
1063
|
+
|
1075
1064
|
Class variables are shared down the inheritance tree. Class instance variables are not shared, but they are not inherited either. The macros +class_inheritable_reader+, +class_inheritable_writer+, and +class_inheritable_accessor+ provide accessors for class-level data which is inherited but not shared with children:
|
1076
1065
|
|
1077
1066
|
<ruby>
|
@@ -1234,7 +1223,7 @@ NOTE: Defined in +active_support/core_ext/string/output_safety.rb+.
|
|
1234
1223
|
|
1235
1224
|
h4. +squish+
|
1236
1225
|
|
1237
|
-
The method +
|
1226
|
+
The method +squish+ strips leading and trailing whitespace, and substitutes runs of whitespace with a single space each:
|
1238
1227
|
|
1239
1228
|
<ruby>
|
1240
1229
|
" \n foo\n\r \t bar \n".squish # => "foo bar"
|
@@ -1277,6 +1266,15 @@ WARNING: The option +:separator+ can't be a regexp.
|
|
1277
1266
|
|
1278
1267
|
NOTE: Defined in +active_support/core_ext/string/filters.rb+.
|
1279
1268
|
|
1269
|
+
h4. +inquiry+
|
1270
|
+
|
1271
|
+
The <tt>inquiry</tt> method converts a string into a +StringInquirer+ object making equality checks prettier.
|
1272
|
+
|
1273
|
+
<ruby>
|
1274
|
+
"production".inquiry.production? # => true
|
1275
|
+
"active".inquiry.inactive? # => false
|
1276
|
+
</ruby>
|
1277
|
+
|
1280
1278
|
h4. Key-based Interpolation
|
1281
1279
|
|
1282
1280
|
In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:
|
@@ -1291,7 +1289,7 @@ Active Support adds that functionality to <tt>%</tt> in previous versions of Rub
|
|
1291
1289
|
|
1292
1290
|
NOTE: Defined in +active_support/core_ext/string/interpolation.rb+.
|
1293
1291
|
|
1294
|
-
h4. +starts_with?+ and +
|
1292
|
+
h4. +starts_with?+ and +ends_with?+
|
1295
1293
|
|
1296
1294
|
Active Support defines 3rd person aliases of +String#start_with?+ and +String#end_with?+:
|
1297
1295
|
|
@@ -1595,7 +1593,7 @@ The method +tableize+ is +underscore+ followed by +pluralize+.
|
|
1595
1593
|
"InvoiceLine".tableize # => "invoice_lines"
|
1596
1594
|
</ruby>
|
1597
1595
|
|
1598
|
-
As a rule of thumb, +tableize+ returns the table name that corresponds to a given model for simple cases. The actual implementation in Active Record is not straight +tableize+ indeed, because it also demodulizes
|
1596
|
+
As a rule of thumb, +tableize+ returns the table name that corresponds to a given model for simple cases. The actual implementation in Active Record is not straight +tableize+ indeed, because it also demodulizes the class name and checks a few options that may affect the returned string.
|
1599
1597
|
|
1600
1598
|
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1601
1599
|
|
@@ -1843,7 +1841,7 @@ h3. Extensions to +Float+
|
|
1843
1841
|
|
1844
1842
|
h4. +round+
|
1845
1843
|
|
1846
|
-
The built-in method +Float#round+ rounds a float to the nearest integer.
|
1844
|
+
The built-in method +Float#round+ rounds a float to the nearest integer. In Ruby 1.9 this method takes an optional argument to let you specify a precision. Active Support adds that functionality to +round+ in previous versions of Ruby:
|
1847
1845
|
|
1848
1846
|
<ruby>
|
1849
1847
|
Math::E.round(4) # => 2.7183
|
@@ -1895,7 +1893,7 @@ The sum of an empty collection is zero by default, but this is customizable:
|
|
1895
1893
|
[].sum(1) # => 1
|
1896
1894
|
</ruby>
|
1897
1895
|
|
1898
|
-
If a block is given +sum+ becomes an iterator that yields the elements of the collection and sums the returned values:
|
1896
|
+
If a block is given, +sum+ becomes an iterator that yields the elements of the collection and sums the returned values:
|
1899
1897
|
|
1900
1898
|
<ruby>
|
1901
1899
|
(1..5).sum {|n| n * 2 } # => 30
|
@@ -1923,7 +1921,7 @@ h4. +each_with_object+
|
|
1923
1921
|
The +inject+ method offers iteration with an accumulator:
|
1924
1922
|
|
1925
1923
|
<ruby>
|
1926
|
-
[2, 3, 4].inject(1) {|
|
1924
|
+
[2, 3, 4].inject(1) {|product, i| product*i } # => 24
|
1927
1925
|
</ruby>
|
1928
1926
|
|
1929
1927
|
The block is expected to return the value for the accumulator in the next iteration, and this makes building mutable objects a bit cumbersome:
|
@@ -1969,7 +1967,7 @@ The method +many?+ is shorthand for +collection.size > 1+:
|
|
1969
1967
|
<% end %>
|
1970
1968
|
</erb>
|
1971
1969
|
|
1972
|
-
If an optional block is given +many?+ only takes into account those elements that return true:
|
1970
|
+
If an optional block is given, +many?+ only takes into account those elements that return true:
|
1973
1971
|
|
1974
1972
|
<ruby>
|
1975
1973
|
@see_more = videos.many? {|video| video.category == params[:category]}
|
@@ -1979,7 +1977,7 @@ NOTE: Defined in +active_support/core_ext/enumerable.rb+.
|
|
1979
1977
|
|
1980
1978
|
h4. +exclude?+
|
1981
1979
|
|
1982
|
-
The predicate +exclude?+ tests whether a given object does *not* belong to the collection. It is the negation of the
|
1980
|
+
The predicate +exclude?+ tests whether a given object does *not* belong to the collection. It is the negation of the built-in +include?+:
|
1983
1981
|
|
1984
1982
|
<ruby>
|
1985
1983
|
to_visit << node if visited.exclude?(node)
|
@@ -1998,16 +1996,21 @@ Active Support augments the API of arrays to ease certain ways of accessing them
|
|
1998
1996
|
[].to(7) # => []
|
1999
1997
|
</ruby>
|
2000
1998
|
|
2001
|
-
Similarly, +from+ returns the tail from the element at the passed index
|
1999
|
+
Similarly, +from+ returns the tail from the element at the passed index to the end. If the index is greater than the length of the array, it returns an empty array.
|
2002
2000
|
|
2003
2001
|
<ruby>
|
2004
2002
|
%w(a b c d).from(2) # => %w(c d)
|
2005
|
-
%w(a b c d).from(10) # =>
|
2003
|
+
%w(a b c d).from(10) # => []
|
2006
2004
|
[].from(0) # => []
|
2007
2005
|
</ruby>
|
2008
2006
|
|
2009
2007
|
The methods +second+, +third+, +fourth+, and +fifth+ return the corresponding element (+first+ is built-in). Thanks to social wisdom and positive constructiveness all around, +forty_two+ is also available.
|
2010
2008
|
|
2009
|
+
<ruby>
|
2010
|
+
%w(a b c d).third # => c
|
2011
|
+
%w(a b c d).fifth # => nil
|
2012
|
+
</ruby>
|
2013
|
+
|
2011
2014
|
NOTE: Defined in +active_support/core_ext/array/access.rb+.
|
2012
2015
|
|
2013
2016
|
h4. Random Access
|
@@ -2034,9 +2037,9 @@ User.exists?(:email => params[:email])
|
|
2034
2037
|
|
2035
2038
|
That syntactic sugar is used a lot in Rails to avoid positional arguments where there would be too many, offering instead interfaces that emulate named parameters. In particular it is very idiomatic to use a trailing hash for options.
|
2036
2039
|
|
2037
|
-
If a method expects a variable number of arguments and uses <tt>*</tt> in its declaration, however, such an options hash ends up being an item of the array of arguments, where
|
2040
|
+
If a method expects a variable number of arguments and uses <tt>*</tt> in its declaration, however, such an options hash ends up being an item of the array of arguments, where it loses its role.
|
2038
2041
|
|
2039
|
-
In those cases, you may give an options hash a distinguished treatment with +extract_options!+.
|
2042
|
+
In those cases, you may give an options hash a distinguished treatment with +extract_options!+. This method checks the type of the last item of an array. If it is a hash it pops it and returns it, otherwise it returns an empty hash.
|
2040
2043
|
|
2041
2044
|
Let's see for example the definition of the +caches_action+ controller macro:
|
2042
2045
|
|
@@ -2103,7 +2106,7 @@ h5. +to_xml+
|
|
2103
2106
|
The method +to_xml+ returns a string containing an XML representation of its receiver:
|
2104
2107
|
|
2105
2108
|
<ruby>
|
2106
|
-
Contributor.
|
2109
|
+
Contributor.limit(2).order(:rank).to_xml
|
2107
2110
|
# =>
|
2108
2111
|
# <?xml version="1.0" encoding="UTF-8"?>
|
2109
2112
|
# <contributors type="array">
|
@@ -2178,7 +2181,7 @@ The name of children nodes is by default the name of the root node singularized.
|
|
2178
2181
|
The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can configure your own builder via the <tt>:builder</tt> option. The method also accepts options like <tt>:dasherize</tt> and friends, they are forwarded to the builder:
|
2179
2182
|
|
2180
2183
|
<ruby>
|
2181
|
-
Contributor.
|
2184
|
+
Contributor.limit(2).order(:rank).to_xml(:skip_types => true)
|
2182
2185
|
# =>
|
2183
2186
|
# <?xml version="1.0" encoding="UTF-8"?>
|
2184
2187
|
# <contributors>
|
@@ -2217,7 +2220,7 @@ Array.wrap(0) # => [0]
|
|
2217
2220
|
|
2218
2221
|
This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
|
2219
2222
|
|
2220
|
-
* If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt> moves on to try +to_a+ if the returned value is +nil+, but <tt>
|
2223
|
+
* If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt> moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns +nil+ right away.
|
2221
2224
|
* If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt> raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
|
2222
2225
|
* It does not call +to_a+ on the argument, though special-cases +nil+ to return an empty array.
|
2223
2226
|
|
@@ -2740,6 +2743,14 @@ WARNING: The original +Range#include?+ is still the one aliased to +Range#===+.
|
|
2740
2743
|
|
2741
2744
|
NOTE: Defined in +active_support/core_ext/range/include_range.rb+.
|
2742
2745
|
|
2746
|
+
h4. +cover?+
|
2747
|
+
|
2748
|
+
Ruby 1.9 provides +cover?+, and Active Support defines it for previous versions as an alias for +include?+.
|
2749
|
+
|
2750
|
+
The method +include?+ in Ruby 1.9 is different from the one in 1.8 for non-numeric ranges: instead of being based on comparisons between the value and the range's endpoints, it walks the range with +succ+ looking for value. This works better for ranges with holes, but it has different complexity and may not finish in some other cases.
|
2751
|
+
|
2752
|
+
In Ruby 1.9 the old behavior is still available in the new +cover?+, which Active Support backports for forward compatibility. For example, Rails uses +cover?+ for ranges in +validates_inclusion_of+.
|
2753
|
+
|
2743
2754
|
h4. +overlaps?+
|
2744
2755
|
|
2745
2756
|
The method +Range#overlaps?+ says whether any two given ranges have non-void intersection:
|
@@ -2867,9 +2878,9 @@ d.end_of_week # => Sun, 09 May 2010
|
|
2867
2878
|
|
2868
2879
|
+beginning_of_week+ is aliased to +monday+ and +at_beginning_of_week+. +end_of_week+ is aliased to +sunday+ and +at_end_of_week+.
|
2869
2880
|
|
2870
|
-
h6. +next_week+
|
2881
|
+
h6. +prev_week+, +next_week+
|
2871
2882
|
|
2872
|
-
+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
|
2883
|
+
The method +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:
|
2873
2884
|
|
2874
2885
|
<ruby>
|
2875
2886
|
d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
|
@@ -2877,6 +2888,14 @@ d.next_week # => Mon, 10 May 2010
|
|
2877
2888
|
d.next_week(:saturday) # => Sat, 15 May 2010
|
2878
2889
|
</ruby>
|
2879
2890
|
|
2891
|
+
The method +prev_week+ is analogous:
|
2892
|
+
|
2893
|
+
<ruby>
|
2894
|
+
d.prev_week # => Mon, 26 Apr 2010
|
2895
|
+
d.prev_week(:saturday) # => Sat, 01 May 2010
|
2896
|
+
d.prev_week(:friday) # => Fri, 30 Apr 2010
|
2897
|
+
</ruby>
|
2898
|
+
|
2880
2899
|
h6. +beginning_of_month+, +end_of_month+
|
2881
2900
|
|
2882
2901
|
The methods +beginning_of_month+ and +end_of_month+ return the dates for the beginning and end of the month:
|
@@ -2954,6 +2973,15 @@ Date.new(2010, 4, 30).months_ago(2) # => Sun, 28 Feb 2010
|
|
2954
2973
|
Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010
|
2955
2974
|
</ruby>
|
2956
2975
|
|
2976
|
+
h6. +weeks_ago+
|
2977
|
+
|
2978
|
+
The method +weeks_ago+ works analogously for weeks:
|
2979
|
+
|
2980
|
+
<ruby>
|
2981
|
+
Date.new(2010, 5, 24).weeks_ago(1) # => Mon, 17 May 2010
|
2982
|
+
Date.new(2010, 5, 24).weeks_ago(2) # => Mon, 10 May 2010
|
2983
|
+
</ruby>
|
2984
|
+
|
2957
2985
|
h6. +advance+
|
2958
2986
|
|
2959
2987
|
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:
|
@@ -3075,6 +3103,8 @@ yesterday
|
|
3075
3103
|
tomorrow
|
3076
3104
|
beginning_of_week (monday, at_beginning_of_week)
|
3077
3105
|
end_on_week (at_end_of_week)
|
3106
|
+
weeks_ago
|
3107
|
+
prev_week
|
3078
3108
|
next_week
|
3079
3109
|
months_ago
|
3080
3110
|
months_since
|
@@ -3228,7 +3258,7 @@ h3. Extensions to +Time+
|
|
3228
3258
|
|
3229
3259
|
h4(#time-calculations). Calculations
|
3230
3260
|
|
3231
|
-
NOTE: All the following methods are defined in +active_support/core_ext/
|
3261
|
+
NOTE: All the following methods are defined in +active_support/core_ext/time/calculations.rb+.
|
3232
3262
|
|
3233
3263
|
Active Support adds to +Time+ many of the methods available for +DateTime+:
|
3234
3264
|
|
@@ -3247,6 +3277,8 @@ beginning_of_day (midnight, at_midnight, at_beginning_of_day)
|
|
3247
3277
|
end_of_day
|
3248
3278
|
beginning_of_week (monday, at_beginning_of_week)
|
3249
3279
|
end_on_week (at_end_of_week)
|
3280
|
+
weeks_ago
|
3281
|
+
prev_week
|
3250
3282
|
next_week
|
3251
3283
|
months_ago
|
3252
3284
|
months_since
|
@@ -3389,11 +3421,11 @@ h4. +silence+
|
|
3389
3421
|
Silences every log level lesser to the specified one for the duration of the given block. Log level orders are: debug, info, error and fatal.
|
3390
3422
|
|
3391
3423
|
<ruby>
|
3392
|
-
|
3393
|
-
|
3394
|
-
|
3395
|
-
|
3396
|
-
|
3424
|
+
logger = Logger.new("log/development.log")
|
3425
|
+
logger.silence(Logger::INFO) do
|
3426
|
+
logger.debug("In space, no one can hear you scream.")
|
3427
|
+
logger.info("Scream all you want, small mailman!")
|
3428
|
+
end
|
3397
3429
|
</ruby>
|
3398
3430
|
|
3399
3431
|
h4. +datetime_format=+
|
@@ -3401,17 +3433,17 @@ h4. +datetime_format=+
|
|
3401
3433
|
Modifies the datetime format output by the formatter class associated with this logger. If the formatter class does not have a +datetime_format+ method then this is ignored.
|
3402
3434
|
|
3403
3435
|
<ruby>
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3407
|
-
|
3408
|
-
|
3409
|
-
end
|
3436
|
+
class Logger::FormatWithTime < Logger::Formatter
|
3437
|
+
cattr_accessor(:datetime_format) { "%Y%m%d%H%m%S" }
|
3438
|
+
|
3439
|
+
def self.call(severity, timestamp, progname, msg)
|
3440
|
+
"#{timestamp.strftime(datetime_format)} -- #{String === msg ? msg : msg.inspect}\n"
|
3410
3441
|
end
|
3411
|
-
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3442
|
+
end
|
3443
|
+
|
3444
|
+
logger = Logger.new("log/development.log")
|
3445
|
+
logger.formatter = Logger::FormatWithTime
|
3446
|
+
logger.info("<- is the current time")
|
3415
3447
|
</ruby>
|
3416
3448
|
|
3417
3449
|
NOTE: Defined in +active_support/core_ext/logger.rb+.
|
@@ -1,18 +1,18 @@
|
|
1
1
|
h2. AJAX on Rails
|
2
2
|
|
3
|
-
This guide covers the built-in Ajax/
|
3
|
+
This guide covers the built-in Ajax/JavaScript functionality of Rails (and more); it will enable you to create rich and dynamic AJAX applications with ease! We will cover the following topics:
|
4
4
|
|
5
5
|
* Quick introduction to AJAX and related technologies
|
6
|
-
* Handling
|
7
|
-
* Testing
|
6
|
+
* Handling JavaScript the Rails way: Rails helpers, Prototype and script.aculo.us
|
7
|
+
* Testing JavaScript functionality
|
8
8
|
|
9
9
|
endprologue.
|
10
10
|
|
11
11
|
h3. Hello AJAX - a Quick Intro
|
12
12
|
|
13
|
-
|
13
|
+
You'll need the basics of DOM, HTTP requests and other topics discussed here to really understand Ajax on Rails.
|
14
14
|
|
15
|
-
h4. Asynchronous
|
15
|
+
h4. Asynchronous JavaScript + XML
|
16
16
|
|
17
17
|
Basic terminology, new style of creating web apps
|
18
18
|
|
@@ -31,7 +31,7 @@ How do 'standard' and AJAX requests differ, why does this matter for understandi
|
|
31
31
|
|
32
32
|
h3. Built-in Rails Helpers
|
33
33
|
|
34
|
-
Rails'
|
34
|
+
Rails' JavaScript framework of choice is "Prototype":http://www.prototypejs.org. Prototype is a generic-purpose JavaScript framework that aims to ease the development of dynamic web applications by offering DOM manipulation, AJAX and other JavaScript functionality ranging from utility functions to object oriented constructs. It is not specifically written for any language, so Rails provides a set of helpers to enable seamless integration of Prototype with your Rails views.
|
35
35
|
|
36
36
|
To get access to these helpers, all you have to do is to include the prototype framework in your pages - typically in your master layout, application.html.erb - like so:
|
37
37
|
<ruby>
|
@@ -42,7 +42,7 @@ You are ready to add some AJAX love to your Rails app!
|
|
42
42
|
|
43
43
|
h4. The Quintessential AJAX Rails Helper: link_to_remote
|
44
44
|
|
45
|
-
Let's start with
|
45
|
+
Let's start with what is probably the most often used helper: +link_to_remote+. It has an interesting feature from the documentation point of view: the options supplied to +link_to_remote+ are shared by all other AJAX helpers, so learning the mechanics and options of +link_to_remote+ is a great help when using other helpers.
|
46
46
|
|
47
47
|
The signature of +link_to_remote+ function is the same as that of the standard +link_to+ helper:
|
48
48
|
|
@@ -62,7 +62,7 @@ link_to_remote "Add to cart",
|
|
62
62
|
|
63
63
|
* The second parameter, the +options+ hash is the most interesting part as it has the AJAX specific stuff:
|
64
64
|
** *:url* This is the only parameter that is always required to generate the simplest remote link (technically speaking, it is not required, you can pass an empty +options+ hash to +link_to_remote+ - but in this case the URL used for the POST request will be equal to your current URL which is probably not your intention). This URL points to your AJAX action handler. The URL is typically specified by Rails REST view helpers, but you can use the +url_for+ format too.
|
65
|
-
** *:update*
|
65
|
+
** *:update* Specifying a DOM id of the element we would like to update. The above example demonstrates the simplest way of accomplishing this - however, we are in trouble if the server responds with an error message because that will be injected into the page too! However, Rails has a solution for this situation:
|
66
66
|
|
67
67
|
<ruby>
|
68
68
|
link_to_remote "Add to cart",
|
@@ -72,7 +72,7 @@ link_to_remote "Add to cart",
|
|
72
72
|
|
73
73
|
If the server returns 200, the output of the above example is equivalent to our first, simple one. However, in case of error, the element with the DOM id +error+ is updated rather than the +cart+ element.
|
74
74
|
|
75
|
-
** *position* By default (i.e. when not specifying this option, like in the examples before) the repsonse is injected into the element with the specified DOM id, replacing the original content of the element
|
75
|
+
** *position* By default (i.e. when not specifying this option, like in the examples before) the repsonse is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the +position+ parameter, with four possibilities:
|
76
76
|
*** +:before+ Inserts the response text just before the target element. More precisely, it creates a text node from the response and inserts it as the left sibling of the target element.
|
77
77
|
*** +:after+ Similar behavior to +:before+, but in this case the response is inserted after the target element.
|
78
78
|
*** +:top+ Inserts the text into the target element, before it's original content. If the target element was empty, this is equivalent with not specifying +:position+ at all.
|
@@ -136,7 +136,7 @@ link_to_remote "Add new item",
|
|
136
136
|
:before => "$('progress').show()",
|
137
137
|
:complete => "$('progress').hide()",
|
138
138
|
:success => "display_item_added(request)",
|
139
|
-
:failure => "display_error(request)"
|
139
|
+
:failure => "display_error(request)"
|
140
140
|
</ruby>
|
141
141
|
** *:type* If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the +:type+ option with the value of +:synchronous+.
|
142
142
|
* Finally, using the +html_options+ parameter you can add HTML attributes to the generated tag. It works like the same parameter of the +link_to+ helper. There are interesting side effects for the +href+ and +onclick+ parameters though:
|
@@ -153,7 +153,7 @@ There are three different ways of adding AJAX forms to your view using Rails Pro
|
|
153
153
|
* +form_remote_tag+ AJAXifies the form by serializing and sending it's data in the background
|
154
154
|
* +submit_to_remote+ and +button_to_remote+ is more rarely used than the previous two. Rather than creating an AJAX form, you add a button/input
|
155
155
|
|
156
|
-
Let's
|
156
|
+
Let's see them in action one by one!
|
157
157
|
|
158
158
|
h5. +remote_form_for+
|
159
159
|
|
@@ -178,12 +178,7 @@ h5. +remote_function+
|
|
178
178
|
|
179
179
|
h5. +update_page+
|
180
180
|
|
181
|
-
|
182
|
-
h3. JavaScript the Rails way: RJS
|
183
|
-
|
184
|
-
In the last section we sent some AJAX requests to the server, and inserted the HTML response into the page (with the +:update+ option). However, sometimes a more complicated interaction with the page is needed, which you can either achieve with JavaScript... or with RJS! You are sending JavaScript instructions to the server in both cases, but while in the former case you have to write vanilla JavaScript, in the second you can code Rails, and sit back while Rails generates the JavaScript for you - so basically RJS is a Ruby DSL to write JavaScript in your Rails code.
|
185
|
-
|
186
|
-
h4. Javascript without RJS
|
181
|
+
h4. Serving JavaScript
|
187
182
|
|
188
183
|
First we'll check out how to send JavaScript to the server manually. You are practically never going to need this, but it's interesting to understand what's going on under the hood.
|
189
184
|
|
@@ -198,140 +193,10 @@ end
|
|
198
193
|
|
199
194
|
What happens here is that by specifying the Content-Type header variable, we instruct the browser to evaluate the text we are sending over (rather than displaying it as plain text, which is the default behavior).
|
200
195
|
|
201
|
-
h4. Inline RJS
|
202
|
-
|
203
|
-
As we said, the purpose of RJS is to write Ruby which is then auto-magically turned into JavaScript by Rails. The above example didn't look too Ruby-esque so let's see how to do it the Rails way:
|
204
|
-
|
205
|
-
<ruby>
|
206
|
-
def javascript_test
|
207
|
-
render :update do |page|
|
208
|
-
page.alert "Hello from inline RJS"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
</ruby>
|
212
|
-
|
213
|
-
The above code snippet does exactly the same as the one in the previous section - going about it much more elegantly though. You don't need to worry about headers,write ugly JavaScript code into a string etc. When the first parameter to +render+ is +:update+, Rails expects a block with a single parameter (+page+ in our case, which is the traditional naming convention) which is an instance of the JavaScriptGenerator:"http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html" object. As it's name suggests, JavaScriptGenerator is responsible for generating JavaScript from your Ruby code. You can execute multiple method calls on the +page+ instance - it's all turned into JavaScript code and sent to the server with the appropriate Content Type, "text/javascript".
|
214
|
-
|
215
|
-
h4. RJS Templates
|
216
|
-
|
217
|
-
If you don't want to clutter your controllers with view code (especially when your inline RJS is more than a few lines), you can move your RJS code to a template file. RJS templates should go to the +/app/views/+ directory, just as +.html.erb+ or any other view files of the appropriate controller, conventionally named +js.rjs+.
|
218
|
-
|
219
|
-
To rewrite the above example, you can leave the body of the action empty, and create a RJS template named +javascript_test.js.rjs+, containing the following line:
|
220
|
-
|
221
|
-
<ruby>
|
222
|
-
page.alert "Hello from inline RJS"
|
223
|
-
</ruby>
|
224
|
-
|
225
|
-
h4. RJS Reference
|
226
|
-
|
227
|
-
In this section we'll go through the methods RJS offers.
|
228
|
-
|
229
|
-
h5. JavaScriptGenerator Methods
|
230
|
-
|
231
|
-
h6. DOM Element Manipulation
|
232
|
-
|
233
|
-
It is possible to manipulate multiple elements at once through the +page+ JavaScriptGenerator instance. Let's see this in action:
|
234
|
-
|
235
|
-
<ruby>
|
236
|
-
page.show :div_one, :div_two
|
237
|
-
page.hide :div_one
|
238
|
-
page.remove :div_one, :div_two, :div_three
|
239
|
-
page.toggle :other_div
|
240
|
-
</ruby>
|
241
|
-
|
242
|
-
The above methods (+show+, +hide+, +remove+, +toggle+) have the same semantics as the Prototype methods of the same name. You can pass an arbitrary number (but at least one) of DOM ids to these calls.
|
243
|
-
|
244
|
-
|
245
|
-
h6. Inserting and Replacing Content
|
246
|
-
|
247
|
-
You can insert content into an element on the page with the +insert_html+ method:
|
248
|
-
|
249
|
-
<ruby>
|
250
|
-
page.insert_html :top, :result, '42'
|
251
|
-
</ruby>
|
252
|
-
|
253
|
-
The first parameter is the position of the new content relative to the element specified by the second parameter, a DOM id.
|
254
|
-
|
255
|
-
Position can be one of these four values:
|
256
|
-
|
257
|
-
*** +:before+ Inserts the response text just before the target element.
|
258
|
-
*** +:after+ The response is inserted after the target element.
|
259
|
-
*** +:top+ Inserts the text into the target element, before it's original content.
|
260
|
-
*** +:bottom+ The counterpart of +:top+: the response is inserted after the target element's original content.
|
261
|
-
|
262
|
-
The third parameter can either be a string, or a hash of options to be passed to ActionView::Base#render - for example:
|
263
|
-
|
264
|
-
<ruby>
|
265
|
-
page.insert_html :top, :result, :partial => "the_answer"
|
266
|
-
</ruby>
|
267
|
-
|
268
|
-
You can replace the contents (innerHTML) of an element with the +replace_html+ method. The only difference is that since it's clear where should the new content go, there is no need for a position parameter - so +replace_html+ takes only two arguments,
|
269
|
-
the DOM id of the element you wish to modify and a string or a hash of options to be passed to ActionView::Base#render.
|
270
|
-
|
271
|
-
h6. Delay
|
272
|
-
|
273
|
-
You can delay the execution of a block of code with +delay+:
|
274
|
-
|
275
|
-
<ruby>
|
276
|
-
page.delay(10) { page.alert('Hey! Just waited 10 seconds') }
|
277
|
-
</ruby>
|
278
|
-
|
279
|
-
+delay+ takes one parameter (time to wait in seconds) and a block which will be executed after the specified time has passed - whatever else follows a +page.delay+ line is executed immediately, the delay affects only the code in the block.
|
280
|
-
|
281
|
-
h6. Reloading and Redirecting
|
282
|
-
|
283
|
-
You can reload the page with the +reload+ method:
|
284
|
-
|
285
|
-
<ruby>
|
286
|
-
page.reload
|
287
|
-
</ruby>
|
288
|
-
|
289
|
-
When using AJAX, you can't rely on the standard +redirect_to+ controller method - you have to use the +page+'s instance method, also called +redirect_to+:
|
290
|
-
|
291
|
-
<ruby>
|
292
|
-
page.redirect_to some_url
|
293
|
-
</ruby>
|
294
|
-
|
295
|
-
h6. Generating Arbitrary JavaScript
|
296
|
-
|
297
|
-
Sometimes even the full power of RJS is not enough to accomplish everything, but you still don't want to drop to pure JavaScript. A nice golden mean is offered by the combination of +<<+, +assign+ and +call+ methods:
|
298
|
-
|
299
|
-
<ruby>
|
300
|
-
page << "alert('1+1 equals 3')"
|
301
|
-
</ruby>
|
302
|
-
|
303
|
-
So +<<+ is used to execute an arbitrary JavaScript statement, passed as string to the method. The above code is equivalent to:
|
304
|
-
|
305
|
-
<ruby>
|
306
|
-
page.assign :result, 3
|
307
|
-
page.call :alert, '1+1 equals ' + result
|
308
|
-
</ruby>
|
309
|
-
|
310
|
-
+assign+ simply assigns a value to a variable. +call+ is similar to +<<+ with a slightly different syntax: the first parameter is the name of the function to call, followed by the list of parameters passed to the function.
|
311
|
-
|
312
|
-
h6. Class Proxies
|
313
|
-
|
314
|
-
h5. Element Proxies
|
315
|
-
|
316
|
-
h5. Collection Proxies
|
317
|
-
|
318
|
-
h5. RJS Helpers
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
h3. I Want my Yellow Thingy: Quick overview of Script.aculo.us
|
323
|
-
|
324
|
-
h4. Introduction
|
325
|
-
|
326
|
-
h4. Visual Effects
|
327
|
-
|
328
|
-
h4. Drag and Drop
|
329
|
-
|
330
|
-
|
331
196
|
|
332
|
-
h3. Testing
|
197
|
+
h3. Testing JavaScript
|
333
198
|
|
334
|
-
|
199
|
+
JavaScript testing reminds me the definition of the world 'classic' by Mark Twain: "A classic is something that everybody wants to have read and nobody wants to read." It's similar with JavaScript testing: everyone would like to have it, yet it's not done by too much developers as it is tedious, complicated, there is a proliferation of tools and no consensus/accepted best practices, but we will nevertheless take a stab at it:
|
335
200
|
|
336
201
|
* (Fire)Watir
|
337
202
|
* Selenium
|
@@ -339,4 +204,4 @@ Javascript testing reminds me the definition of the world 'classic' by Mark Twai
|
|
339
204
|
* Cucumber+Webrat
|
340
205
|
* Mention stuff like screw.unit/jsSpec
|
341
206
|
|
342
|
-
Note to self: check out the RailsConf JS testing video
|
207
|
+
Note to self: check out the RailsConf JS testing video
|