diff options
Diffstat (limited to 'guides/source')
-rw-r--r-- | guides/source/4_0_release_notes.textile | 591 | ||||
-rw-r--r-- | guides/source/action_view_overview.textile | 66 | ||||
-rw-r--r-- | guides/source/active_record_querying.textile | 48 | ||||
-rw-r--r-- | guides/source/active_support_core_extensions.textile | 96 | ||||
-rw-r--r-- | guides/source/active_support_instrumentation.textile | 4 | ||||
-rw-r--r-- | guides/source/command_line.textile | 198 | ||||
-rw-r--r-- | guides/source/contributing_to_ruby_on_rails.textile | 36 | ||||
-rw-r--r-- | guides/source/engines.textile | 6 | ||||
-rw-r--r-- | guides/source/getting_started.textile | 54 | ||||
-rw-r--r-- | guides/source/initialization.textile | 159 | ||||
-rw-r--r-- | guides/source/migrations.textile | 3 | ||||
-rw-r--r-- | guides/source/rails_on_rack.textile | 62 | ||||
-rw-r--r-- | guides/source/routing.textile | 16 | ||||
-rw-r--r-- | guides/source/ruby_on_rails_guides_guidelines.textile | 24 | ||||
-rw-r--r-- | guides/source/security.textile | 79 | ||||
-rw-r--r-- | guides/source/upgrading_ruby_on_rails.textile | 20 |
16 files changed, 1170 insertions, 292 deletions
diff --git a/guides/source/4_0_release_notes.textile b/guides/source/4_0_release_notes.textile new file mode 100644 index 0000000000..1ed6006b6b --- /dev/null +++ b/guides/source/4_0_release_notes.textile @@ -0,0 +1,591 @@ +h2. Ruby on Rails 4.0 Release Notes + +Highlights in Rails 4.0: + +These release notes cover the major changes, but do not include each bug-fix and changes. If you want to see everything, check out the "list of commits":https://github.com/rails/rails/commits/master in the main Rails repository on GitHub. + +endprologue. + +h3. Upgrading to Rails 4.0 + +TODO. This is a WIP guide. + +If you're upgrading an existing application, it's a great idea to have good test coverage before going in. You should also first upgrade to Rails 3.2 in case you haven't and make sure your application still runs as expected before attempting an update to Rails 4.0. Then take heed of the following changes: + +h4. Rails 4.0 requires at least Ruby 1.9.3 + +Rails 4.0 requires Ruby 1.9.3 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. + +h4. What to update in your apps + +* Update your Gemfile to depend on +** <tt>rails = 4.0.0</tt> +** <tt>sass-rails ~> 3.2.3</tt> +** <tt>coffee-rails ~> 3.2.1</tt> +** <tt>uglifier >= 1.0.3</tt> + +TODO: Update the versions above. + +* Rails 4.0 removes <tt>vendor/plugins</tt> completely. You have to replace these plugins by extracting them as gems and adding them in your Gemfile. If you choose not to make them gems, you can move them into, say, <tt>lib/my_plugin/*</tt> and add an appropriate initializer in <tt>config/initializers/my_plugin.rb</tt>. + +TODO: Configuration changes in environment files + +h3. Creating a Rails 4.0 application + +<shell> +# You should have the 'rails' rubygem installed +$ rails new myapp +$ cd myapp +</shell> + +h4. Vendoring Gems + +Rails now uses a +Gemfile+ in the application root to determine the gems you require for your application to start. This +Gemfile+ is processed by the "Bundler":https://github.com/carlhuda/bundler gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. + +More information: "Bundler homepage":http://gembundler.com + +h4. Living on the Edge + ++Bundler+ and +Gemfile+ makes freezing your Rails application easy as pie with the new dedicated +bundle+ command. If you want to bundle straight from the Git repository, you can pass the +--edge+ flag: + +<shell> +$ rails new myapp --edge +</shell> + +If you have a local checkout of the Rails repository and want to generate an application using that, you can pass the +--dev+ flag: + +<shell> +$ ruby /path/to/rails/railties/bin/rails new myapp --dev +</shell> + +h3. Major Features + +h3. Documentation + +h3. Railties + +* Add runner to <tt>Rails::Railtie</tt> as a hook called just after runner starts. + +* Add <tt>/rails/info/routes</tt> path which displays the same information as +rake routes+. + +* Improved +rake routes+ output for redirects. + +* Load all environments available in config.paths["config/environments"]. + +* The application generator generates <tt>public/humans.txt</tt> with some basic data. + +* Add <tt>config.queue_consumer</tt> to allow the default consumer to be configurable. + +* Add <tt>Rails.queue</tt> as an interface with a default implementation that consumes jobs in a separate thread. + +* Remove <tt>Rack::SSL</tt> in favour of <tt>ActionDispatch::SSL</tt>. + +* Allow to set class that will be used to run as a console, other than IRB, with <tt>Rails.application.config.console=</tt>. It's best to add it to console block. + +<ruby> +# it can be added to config/application.rb +console do + # this block is called only when running console, + # so we can safely require pry here + require "pry" + config.console = Pry +end +</ruby> + +* Add convenience hide! method to Rails generators to hide current generator + namespace from showing when running rails generate. + +* Scaffold now uses +content_tag_for+ in <tt>index.html.erb</tt>. + +* <tt>Rails::Plugin</tt> is removed. Instead of adding plugins to vendor/plugins use gems or bundler with path or git dependencies. + +h4(#railties_deprecations). Deprecations + +h3. Action Mailer + +* No changes. + +h3. Action Pack + +h4. Action Controller + +* Extracted redirect logic from <tt>ActionController::ForceSSL::ClassMethods.force_ssl</tt> into <tt>ActionController::ForceSSL#force_ssl_redirect</tt>. + +* URL path parameters with invalid encoding now raise <tt>ActionController::BadRequest</tt>. + +* Malformed query and request parameter hashes now raise <tt>ActionController::BadRequest</tt>. + +* +respond_to+ and +respond_with+ now raise <tt>ActionController::UnknownFormat</tt> instead of directly returning head 406. The exception is rescued and converted to 406 in the exception handling middleware. + +* JSONP now uses mimetype <tt>application/javascript</tt> instead of <tt>application/json</tt>. + +* Session arguments passed to process calls in functional tests are now merged into the existing session, whereas previously they would replace the existing session. This change may break some existing tests if they are asserting the exact contents of the session but should not break existing tests that only assert individual keys. + +* Forms of persisted records use always PATCH (via the _method hack). + +* For resources, both PATCH and PUT are routed to the update action. + +* Don't ignore +force_ssl+ in development. This is a change of behavior - use a :if condition to recreate the old behavior. + +<ruby> +class AccountsController < ApplicationController + force_ssl :if => :ssl_configured? + + def ssl_configured? + !Rails.env.development? + end +end +</ruby> + +h5(#actioncontroller_deprecations). Deprecations + +* Deprecated ActionController::Integration in favour of ActionDispatch::Integration + +* Deprecated ActionController::IntegrationTest in favour of ActionDispatch::IntegrationTest + +* Deprecated ActionController::PerformanceTest in favour of ActionDispatch::PerformanceTest + +* Deprecated ActionController::AbstractRequest in favour of ActionDispatch::Request + +* Deprecated ActionController::Request in favour of ActionDispatch::Request + +* Deprecated ActionController::AbstractResponse in favour of ActionDispatch::Response + +* Deprecated ActionController::Response in favour of ActionDispatch::Response + +* Deprecated ActionController::Routing in favour of ActionDispatch::Routing + +h4. Action Dispatch + +* Added <tt>ActionDispatch::SSL</tt> middleware that when included force all the requests to be under HTTPS protocol. + +* Copy literal route constraints to defaults so that url generation know about them. The copied constraints are :protocol, :subdomain, :domain, :host and :port. + +* Allows +assert_redirected_to+ to match against a regular expression. + +* Add backtrace to development routing error page. + +* +assert_generates+, +assert_recognizes+, and +assert_routing+ all raise +Assertion+ instead of +RoutingError+. + +* Allows the route helper root to take a string argument. For example, <tt>root 'pages#main'</tt> as a shortcut for <tt>root to: 'pages#main'</tt>. + +* Adds support for the PATCH verb: + Request objects respond to patch?. + Routes have a new patch method, and understand :patch in the + existing places where a verb is configured, like :via. + New method patch available in functional tests. + If :patch is the default verb for updates, edits are + tunneled as PATCH rather than as PUT, and routing acts accordingly. + New method patch_via_redirect available in integration tests. + +* Integration tests support the OPTIONS method. + +* +expires_in+ accepts a +must_revalidate+ flag. If true, "must-revalidate" is added to the Cache-Control header. + +* Default responder will now always use your overridden block in respond_with to render your response. + +* Turn off verbose mode of rack-cache, we still have X-Rack-Cache to check that info. + +* Include mounted_helpers (helpers for accessing mounted engines) in <tt>ActionDispatch::IntegrationTest</tt> by default. + +h5(#actiondispatch_deprecations). Deprecations + +h4. Action View + +* Make current object and counter (when it applies) variables accessible when rendering templates with :object / :collection. + +* Allow to lazy load +default_form_builder+ by passing a String instead of a constant. + +* Add index method to +FormBuilder+ class. + +* Adds support for layouts when rendering a partial with a given collection. + +* Remove <tt>:disable_with</tt> in favor of <tt>data-disable-with</tt> option from +submit_tag+, +button_tag+ and +button_to+ helpers. + +* Remove <tt>:mouseover</tt> option from +image_tag+ helper. + +* Templates without a handler extension now raises a deprecation warning but still defaults to ERb. In future releases, it will simply return the template content. + +* Add divider option to +grouped_options_for_select+ to generate a separator optgroup automatically, and deprecate prompt as third argument, in favor of using an options hash. + +* Add +time_field+ and +time_field_tag+ helpers which render an <tt>input[type="time"]</tt> tag. + +* Removed old +text_helper+ apis for +highlight+, +excerpt+ and +word_wrap+. + +* Allow to use mounted_helpers (helpers for accessing mounted engines) in <tt>ActionView::TestCase</tt>. + +* Remove the leading \n added by textarea on +assert_select+. + +* Changed default value for <tt>config.action_view.embed_authenticity_token_in_remote_forms</tt> to false. This change breaks remote forms that need to work also without JavaScript, so if you need such behavior, you can either set it to true or explicitly pass <tt>:authenticity_token => true</tt> in form options. + +* Make possible to use a block in +button_to+ helper if button text is hard to fit into the name parameter: + +<ruby> +<%= button_to [:make_happy, @user] do %> + Make happy <strong><%= @user.name %></strong> +<% end %> +# => "<form method="post" action="/users/1/make_happy" class="button_to"> +# <div> +# <button type="submit"> +# Make happy <strong>Name</strong> +# </button> +# </div> +# </form>" +</ruby> + +* Replace +include_seconds+ boolean argument with <tt>:include_seconds => true</tt> option in +distance_of_time_in_words+ and +time_ago_in_words+ signature. + +* Remove +button_to_function+ and +link_to_function+ helpers. + +* truncate now always returns an escaped HTML-safe string. The option :escape can be used as false to not escape the result. + +* truncate now accepts a block to show extra content when the text is truncated. + +* Add +week_field+, +week_field_tag+, +month_field+, +month_field_tag+, +datetime_local_field+, +datetime_local_field_tag+, +datetime_field+ and +datetime_field_tag+ helpers. + +* Add +color_field+ and +color_field_tag+ helpers. + +* Add +include_hidden+ option to select tag. With <tt>:include_hidden => false</tt> select with multiple attribute doesn't generate hidden input with blank value. + +* Removed default size option from the +text_field+, +search_field+, +telephone_field+, +url_field+, +email_field+ helpers. + +* Removed default cols and rows options from the +text_area+ helper. + +* Adds +image_url+, +javascript_url+, +stylesheet_url+, +audio_url+, +video_url+, and +font_url+ to assets tag helper. These URL helpers will return the full path to your assets. This is useful when you are going to reference this asset from external host. + +* Allow +value_method+ and +text_method+ arguments from +collection_select+ and +options_from_collection_for_select+ to receive an object that responds to :call, such as a proc, to evaluate the option in the current element context. This works the same way with +collection_radio_buttons+ and +collection_check_boxes+. + +* Add +date_field+ and +date_field_tag+ helpers which render an <tt>input[type="date"]</tt> tag. + +* Add +collection_check_boxes+ form helper, similar to +collection_select+: + +<ruby> +collection_check_boxes :post, :author_ids, Author.all, :id, :name +# Outputs something like: +<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" /> +<label for="post_author_ids_1">D. Heinemeier Hansson</label> +<input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /> +<label for="post_author_ids_2">D. Thomas</label> +<input name="post[author_ids][]" type="hidden" value="" /> +</ruby> + +The label/check_box pairs can be customized with a block. + +* Add +collection_radio_buttons+ form helper, similar to collection_select: + +<ruby> +collection_radio_buttons :post, :author_id, Author.all, :id, :name +# Outputs something like: +<input id="post_author_id_1" name="post[author_id]" type="radio" value="1" /> +<label for="post_author_id_1">D. Heinemeier Hansson</label> +<input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /> +<label for="post_author_id_2">D. Thomas</label> +</ruby> + +The label/radio_button pairs can be customized with a block. + +* +check_box+ with :form HTML5 attribute will now replicate the :form attribute to the hidden field as well. + +* label form helper accepts :for => nil to not generate the attribute. + +* Add :format option to +number_to_percentage+. + +* Add <tt>config.action_view.logger</tt> to configure logger for Action View. + +* +check_box+ helper with :disabled => true will generate a disabled hidden field to conform with the HTML convention where disabled fields are not submitted with the form. This is a behavior change, previously the hidden tag had a value of the disabled checkbox. + +* +favicon_link_tag+ helper will now use the favicon in <tt>app/assets</tt> by default. + +* <tt>ActionView::Helpers::TextHelper#highlight</tt> now defaults to the HTML5 +mark+ element. + +h5(#actionview_deprecations). Deprecations + +h4. Sprockets + +Moved into a separate gem <tt>sprockets-rails</tt>. + +h3. Active Record + +* Allow blocks for count with <tt>ActiveRecord::Relation</tt>, to work similar as <tt>Array#count</tt>: <tt>Person.where("age > 26").count { |person| person.gender == 'female' }</tt> + +* Added support to <tt>CollectionAssociation#delete</tt> for passing fixnum or string values as record ids. This finds the records responding to the id and executes delete on them. + +<ruby> +class Person < ActiveRecord::Base + has_many :pets +end + +person.pets.delete("1") # => [#<Pet id: 1>] +person.pets.delete(2, 3) # => [#<Pet id: 2>, #<Pet id: 3>] +</ruby> + +* It's not possible anymore to destroy a model marked as read only. + +* Added ability to <tt>ActiveRecord::Relation#from</tt> to accept other <tt>ActiveRecord::Relation</tt> objects. + +* Added custom coders support for <tt>ActiveRecord::Store</tt>. Now you can set your custom coder like this: + +<ruby>store :settings, accessors: [ :color, :homepage ], coder: JSON</ruby> + +* mysql and mysql2 connections will set SQL_MODE=STRICT_ALL_TABLES by default to avoid silent data loss. This can be disabled by specifying strict: false in your database.yml. + +* Added default order to first to assure consistent results among diferent database engines. Introduced take as a replacement to the old behavior of first. + +* Added an :index option to automatically create indexes for references and belongs_to statements in migrations. The references and belongs_to methods now support an index option that receives either a boolean value or an options hash that is identical to options available to the add_index method: + +<ruby> +create_table :messages do |t| + t.references :person, :index => true +end +</ruby> + +Is the same as: + +<ruby> +create_table :messages do |t| + t.references :person +end +add_index :messages, :person_id +</ruby> + +Generators have also been updated to use the new syntax. + +* Added bang methods for mutating <tt>ActiveRecord::Relation</tt> objects. For example, while <tt>foo.where(:bar)</tt> will return a new object leaving foo unchanged, <tt>foo.where!(:bar)</tt> will mutate the foo object. + +* Added #find_by and #find_by! to mirror the functionality provided by dynamic finders in a way that allows dynamic input more easily: + +<ruby> +Post.find_by name: 'Spartacus', rating: 4 +Post.find_by "published_at < ?", 2.weeks.ago +Post.find_by! name: 'Spartacus' +</ruby> + +* Added <tt>ActiveRecord::Base#slice</tt> to return a hash of the given methods with their names as keys and returned values as values. + +* Remove IdentityMap - IdentityMap has never graduated to be an "enabled-by-default" feature, due to some inconsistencies with associations, as described in this commit: https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. Hence the removal from the codebase, until such issues are fixed. + +* Added a feature to dump/load internal state of SchemaCache instance because we want to boot rails more quickly when we have many models. + +<ruby> +# execute rake task. +RAILS_ENV=production bundle exec rake db:schema:cache:dump +=> generate db/schema_cache.dump + +# add config.use_schema_cache_dump = true in config/production.rb. BTW, true is default. + +# boot rails. +RAILS_ENV=production bundle exec rails server +=> use db/schema_cache.dump + +# If you remove clear dumped cache, execute rake task. +RAILS_ENV=production bundle exec rake db:schema:cache:clear +=> remove db/schema_cache.dump +</ruby> + +* Added support for partial indices to PostgreSQL adapter. + +* The +add_index+ method now supports a +where+ option that receives a string with the partial index criteria. + +* Implemented <tt>ActiveRecord::Relation#none</tt> method which returns a chainable relation with zero records (an instance of the NullRelation class). Any subsequent condition chained to the returned relation will continue generating an empty relation and will not fire any query to the database. + +* Added the <tt>ActiveRecord::NullRelation</tt> class implementing the null object pattern for the Relation class. + +* Added +create_join_table+ migration helper to create HABTM join tables. + +<ruby> +create_join_table :products, :categories +# => +# create_table :categories_products, :id => false do |td| +# td.integer :product_id, :null => false +# td.integer :category_id, :null => false +# end +</ruby> + +* The primary key is always initialized in the @attributes hash to nil (unless another value has been specified). + +* In previous releases, the following would generate a single query with an OUTER JOIN comments, rather than two separate queries: + +<ruby>Post.includes(:comments).where("comments.name = 'foo'")</ruby> + +This behaviour relies on matching SQL string, which is an inherently flawed idea unless we write an SQL parser, which we do not wish to do. Therefore, it is now deprecated. + +To avoid deprecation warnings and for future compatibility, you must explicitly state which tables you reference, when using SQL snippets: + +<ruby>Post.includes(:comments).where("comments.name = 'foo'").references(:comments)</ruby> + +Note that you do not need to explicitly specify references in the following cases, as they can be automatically inferred: + +<ruby> +Post.where(comments: { name: 'foo' }) +Post.where('comments.name' => 'foo') +Post.order('comments.name') +</ruby> + +You also do not need to worry about this unless you are doing eager loading. Basically, don't worry unless you see a deprecation warning or (in future releases) an SQL error due to a missing JOIN. + +* Support for the +schema_info+ table has been dropped. Please switch to +schema_migrations+. + +* Connections *must* be closed at the end of a thread. If not, your connection pool can fill and an exception will be raised. + +* Added the <tt>ActiveRecord::Model</tt> module which can be included in a class as an alternative to inheriting from <tt>ActiveRecord::Base</tt>: + +<ruby> +class Post + include ActiveRecord::Model +end +</ruby> + +* PostgreSQL hstore records can be created. + +* PostgreSQL hstore types are automatically deserialized from the database. + +h4(#activerecord_deprecations). Deprecations + +* Deprecated most of the 'dynamic finder' methods. All dynamic methods except for +find_by_...+ and +find_by_...!+ are deprecated. Here's how you can rewrite the code: + +<ruby> +find_all_by_... can be rewritten using where(...) +find_last_by_... can be rewritten using where(...).last +scoped_by_... can be rewritten using where(...) +find_or_initialize_by_... can be rewritten using where(...).first_or_initialize +find_or_create_by_... can be rewritten using where(...).first_or_create +find_or_create_by_...! can be rewritten using where(...).first_or_create! +</ruby> + +The implementation of the deprecated dynamic finders has been moved to the +active_record_deprecated_finders+ gem. + +* Deprecated the old-style hash based finder API. This means that methods which previously accepted "finder options" no longer do. For example this: + +<ruby>Post.find(:all, :conditions => { :comments_count => 10 }, :limit => 5)</ruby> + +should be rewritten in the new style which has existed since Rails 3: + +<ruby>Post.where(comments_count: 10).limit(5)</ruby> + +Note that as an interim step, it is possible to rewrite the above as: + +<ruby>Post.scoped(:where => { :comments_count => 10 }, :limit => 5)</ruby> + +This could save you a lot of work if there is a lot of old-style finder usage in your application. + +Calling <tt>Post.scoped(options)</tt> is a shortcut for <tt>Post.scoped.merge(options)</tt>. <tt>Relation#merge</tt> now accepts a hash of options, but they must be identical to the names of the equivalent finder method. These are mostly identical to the old-style finder option names, except in the following cases: + +<plain> +:conditions becomes :where +:include becomes :includes +:extend becomes :extending +</plain> + +The code to implement the deprecated features has been moved out to the +active_record_deprecated_finders+ gem. This gem is a dependency of Active Record in Rails 4.0. It will no longer be a dependency from Rails 4.1, but if your app relies on the deprecated features then you can add it to your own Gemfile. It will be maintained by the Rails core team until Rails 5.0 is released. + +* Deprecate eager-evaluated scopes. + + Don't use this: + + scope :red, where(color: 'red') + default_scope where(color: 'red') + + Use this: + + scope :red, -> { where(color: 'red') } + default_scope { where(color: 'red') } + + The former has numerous issues. It is a common newbie gotcha to do the following: + + scope :recent, where(published_at: Time.now - 2.weeks) + + Or a more subtle variant: + + scope :recent, -> { where(published_at: Time.now - 2.weeks) } + scope :recent_red, recent.where(color: 'red') + + Eager scopes are also very complex to implement within Active Record, and there are still bugs. For example, the following does not do what you expect: + + scope :remove_conditions, except(:where) + where(...).remove_conditions # => still has conditions + +* Added deprecation for the :dependent => :restrict association option. + +* Up until now has_many and has_one, :dependent => :restrict option raised a DeleteRestrictionError at the time of destroying the object. Instead, it will add an error on the model. + +* To fix this warning, make sure your code isn't relying on a DeleteRestrictionError and then add config.active_record.dependent_restrict_raises = false to your application config. + +* New rails application would be generated with the config.active_record.dependent_restrict_raises = false in the application config. + +h3. Active Model + +* Passing false hash values to +validates+ will no longer enable the corresponding validators. + +* +ConfirmationValidator+ error messages will attach to <tt>:#{attribute}_confirmation</tt> instead of +attribute+. + +* Added <tt>ActiveModel::Model</tt>, a mixin to make Ruby objects work with Action Pack out of the box. + +* <tt>ActiveModel::Errors#to_json</tt> supports a new parameter <tt>:full_messages</tt>. + +* Trims down the API by removing <tt>valid?</tt> and <tt>errors.full_messages</tt>. + +h4(#activemodel_deprecations). Deprecations + +h3. Active Resource + +* Active Resource is removed from Rails 4.0 and is now a separate gem. TODO: put a link to the gem here. + +h3. Active Support + +* <tt>ActionView::Helpers::NumberHelper</tt> methods have been moved to <tt>ActiveSupport::NumberHelper</tt> and are now available via <tt>Numeric#to_s</tt>. + +* <tt>Numeric#to_s</tt> now accepts the formatting options :phone, :currency, :percentage, :delimited, :rounded, :human, and :human_size. + +* Add <tt>Hash#transform_keys</tt>, <tt>Hash#transform_keys!</tt>, <tt>Hash#deep_transform_keys</tt> and <tt>Hash#deep_transform_keys!</tt>. + +* Changed xml type datetime to dateTime (with upper case letter T). + +* Add <tt>:instance_accessor</tt> option for <tt>class_attribute</tt>. + +* +constantize+ now looks in the ancestor chain. + +* Add <tt>Hash#deep_stringify_keys</tt> and <tt>Hash#deep_stringify_keys!</tt> to convert all keys from a +Hash+ instance into strings. + +* Add <tt>Hash#deep_symbolize_keys</tt> and <tt>Hash#deep_symbolize_keys!</tt> to convert all keys from a +Hash+ instance into symbols. + +* <tt>Object#try</tt> can't call private methods. + +* AS::Callbacks#run_callbacks remove key argument. + +* +deep_dup+ works more expectedly now and duplicates also values in +Hash+ instances and elements in +Array+ instances. + +* Inflector no longer applies ice -> ouse to words like slice, police. + +* Add <tt>ActiveSupport::Deprecations.behavior = :silence</tt> to completely ignore Rails runtime deprecations. + +* Make <tt>Module#delegate</tt> stop using send - can no longer delegate to private methods. + +* AS::Callbacks deprecate :rescuable option. + +* Adds <tt>Integer#ordinal</tt> to get the ordinal suffix string of an integer. + +* AS::Callbacks :per_key option is no longer supported. + +* AS::Callbacks#define_callbacks add :skip_after_callbacks_if_terminated option. + +* Add html_escape_once to ERB::Util, and delegate escape_once tag helper to it. + +* Remove <tt>ActiveSupport::TestCase#pending</tt> method, use +skip+ instead. + +* Deletes the compatibility method <tt>Module#method_names</tt>, use <tt>Module#methods</tt> from now on (which returns symbols). + +* Deletes the compatibility method <tt>Module#instance_method_names</tt>, use <tt>Module#instance_methods</tt> from now on (which returns symbols). + +* Unicode database updated to 6.1.0. + +* Adds +encode_big_decimal_as_string+ option to force JSON serialization of BigDecimals as numeric instead of wrapping them in strings for safety. + +h4(#activesupport_deprecations). Deprecations + +* <tt>BufferedLogger</tt> is deprecated. Use <tt>ActiveSupport::Logger</tt> or the +logger+ from Ruby stdlib. + +* Deprecates the compatibility method <tt>Module#local_constant_names</tt> and use <tt>Module#local_constants</tt> instead (which returns symbols). + +h3. Credits + +See the "full list of contributors to Rails":http://contributors.rubyonrails.org/ for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them. diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile index bde30ba21c..fdfa97effa 100644 --- a/guides/source/action_view_overview.textile +++ b/guides/source/action_view_overview.textile @@ -454,7 +454,7 @@ input("post", "title") # => h4. RecordTagHelper -This module provides methods for generating a container tag, such as a +<div>+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use. +This module provides methods for generating container tags, such as +div+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use. h5. content_tag_for @@ -542,28 +542,28 @@ image_tag("rails.png") # => <img src="http://assets.example.com/images/rails.png h5. register_javascript_expansion -Register one or more JavaScript files to be included when symbol is passed to javascript_include_tag. This method is typically intended to be called from plugin initialization to register JavaScript files that the plugin installed in +public/javascripts+. +Register one or more JavaScript files to be included when symbol is passed to javascript_include_tag. This method is typically intended to be called from plugin initialization to register JavaScript files that the plugin installed in +vendor/assets/javascripts+. <ruby> ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"] javascript_include_tag :monkey # => - <script src="/javascripts/head.js"></script> - <script src="/javascripts/body.js"></script> - <script src="/javascripts/tail.js"></script> + <script src="/assets/head.js"></script> + <script src="/assets/body.js"></script> + <script src="/assets/tail.js"></script> </ruby> h5. register_stylesheet_expansion -Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +public/stylesheets+. +Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +vendor/assets/stylesheets+. <ruby> ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] stylesheet_link_tag :monkey # => - <link href="/stylesheets/head.css" media="screen" rel="stylesheet" /> - <link href="/stylesheets/body.css" media="screen" rel="stylesheet" /> - <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" /> + <link href="/assets/head.css" media="screen" rel="stylesheet" /> + <link href="/assets/body.css" media="screen" rel="stylesheet" /> + <link href="/assets/tail.css" media="screen" rel="stylesheet" /> </ruby> h5. auto_discovery_link_tag @@ -577,44 +577,49 @@ auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "RSS h5. image_path -Computes the path to an image asset in the +public/images+ directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path. +Computes the path to an image asset in the +app/assets/images+ directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path. <ruby> -image_path("edit.png") # => /images/edit.png +image_path("edit.png") # => /assets/edit.png +</ruby> + +Fingerprint will be added to the filename if config.assets.digest is set to true. + +<ruby> +image_path("edit.png") # => /assets/edit-2d1a2db63fc738690021fedb5a65b68e.png </ruby> h5. image_url -Computes the url to an image asset in the +public/images+ directory. This will call +image_path+ internally and merge with your current host or your asset host. +Computes the url to an image asset in the +app/asset/images+ directory. This will call +image_path+ internally and merge with your current host or your asset host. <ruby> -image_url("edit.png") # => http://www.example.com/images/edit.png +image_url("edit.png") # => http://www.example.com/assets/edit.png </ruby> h5. image_tag -Returns an html image tag for the source. The source can be a full path or a file that exists in your +public/images+ directory. +Returns an html image tag for the source. The source can be a full path or a file that exists in your +app/assets/images+ directory. <ruby> -image_tag("icon.png") # => <img src="/images/icon.png" alt="Icon" /> +image_tag("icon.png") # => <img src="/assets/icon.png" alt="Icon" /> </ruby> h5. javascript_include_tag -Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of JavaScript files that exist in your +public/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root. +Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of JavaScript files that exist in your +app/assets/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root. <ruby> -javascript_include_tag "common" # => - <script src="/javascripts/common.js"></script> +javascript_include_tag "common" # => <script src="/assets/common.js"></script> </ruby> -If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +public/javascripts+ directory, it will be included as well. +If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +app/assets/javascripts+ directory, it will be included as well. <ruby> javascript_include_tag :defaults </ruby> -You can also include all JavaScript files in the +public/javascripts+ directory using +:all+ as the source. +You can also include all JavaScript files in the +app/assets/javascripts+ directory using +:all+ as the source. <ruby> javascript_include_tag :all @@ -629,18 +634,18 @@ javascript_include_tag :all, :cache => true # => h5. javascript_path -Computes the path to a JavaScript asset in the +public/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path. +Computes the path to a JavaScript asset in the +app/assets/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path. <ruby> -javascript_path "common" # => /javascripts/common.js +javascript_path "common" # => /assets/common.js </ruby> h5. javascript_url -Computes the url to a JavaScript asset in the +public/javascripts+ directory. This will call +javascript_path+ internally and merge with your current host or your asset host. +Computes the url to a JavaScript asset in the +app/assets/javascripts+ directory. This will call +javascript_path+ internally and merge with your current host or your asset host. <ruby> -javascript_url "common" # => http://www.example.com/javascripts/common.js +javascript_url "common" # => http://www.example.com/assets/common.js </ruby> h5. stylesheet_link_tag @@ -648,8 +653,7 @@ h5. stylesheet_link_tag Returns a stylesheet link tag for the sources specified as arguments. If you don't specify an extension, +.css+ will be appended automatically. <ruby> -stylesheet_link_tag "application" # => - <link href="/stylesheets/application.css" media="screen" rel="stylesheet" /> +stylesheet_link_tag "application" # => <link href="/assets/application.css" media="screen" rel="stylesheet" /> </ruby> You can also include all styles in the stylesheet directory using :all as the source: @@ -662,23 +666,23 @@ You can also cache multiple stylesheets into one file, which requires less HTTP <ruby> stylesheet_link_tag :all, :cache => true - <link href="/stylesheets/all.css" media="screen" rel="stylesheet" /> +# => <link href="/assets/all.css" media="screen" rel="stylesheet" /> </ruby> h5. stylesheet_path -Computes the path to a stylesheet asset in the +public/stylesheets+ directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path. +Computes the path to a stylesheet asset in the +app/assets/stylesheets+ directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path. <ruby> -stylesheet_path "application" # => /stylesheets/application.css +stylesheet_path "application" # => /assets/application.css </ruby> h5. stylesheet_url -Computes the url to a stylesheet asset in the +public/stylesheets+ directory. This will call +stylesheet_path+ internally and merge with your current host or your asset host. +Computes the url to a stylesheet asset in the +app/assets/stylesheets+ directory. This will call +stylesheet_path+ internally and merge with your current host or your asset host. <ruby> -stylesheet_url "application" # => http://www.example.com/stylesheets/application.css +stylesheet_url "application" # => http://www.example.com/assets/application.css </ruby> h4. AtomFeedHelper diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index 294ef25b33..4b14671efc 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -259,6 +259,54 @@ SELECT * FROM clients WHERE (clients.id IN (1,10)) WARNING: <tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for <strong>all</strong> of the supplied primary keys. +h5. take + +<tt>Model.take(limit)</tt> retrieves the first number of records specified by +limit+ without any explicit ordering: + +<ruby> +Client.take(2) +# => [#<Client id: 1, first_name: "Lifo">, + #<Client id: 2, first_name: "Raf">] +</ruby> + +The SQL equivalent of the above is: + +<sql> +SELECT * FROM clients LIMIT 2 +</sql> + +h5. first + +<tt>Model.first(limit)</tt> finds the first number of records specified by +limit+ ordered by primary key: + +<ruby> +Client.first(2) +# => [#<Client id: 1, first_name: "Lifo">, + #<Client id: 2, first_name: "Raf">] +</ruby> + +The SQL equivalent of the above is: + +<sql> +SELECT * FROM clients LIMIT 2 +</sql> + +h5. last + +<tt>Model.last(limit)</tt> finds the number of records specified by +limit+ ordered by primary key in descending order: + +<ruby> +Client.last(2) +# => [#<Client id: 10, first_name: "Ryan">, + #<Client id: 9, first_name: "John">] +</ruby> + +The SQL equivalent of the above is: + +<sql> +SELECT * FROM clients ORDER By id DESC LIMIT 2 +</sql> + h4. Retrieving Multiple Objects in Batches We often need to iterate over a large set of records, as when we send a newsletter to a large set of users, or when we export data. diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index 587f65529e..011a702901 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -156,7 +156,7 @@ NOTE: Defined in +active_support/core_ext/object/duplicable.rb+. h4. +deep_dup+ -The +deep_dup+ method returns deep copy of given object. Normally, when you +dup+ an object that contains other objects, ruby does not +dup+ them. If you have array with a string, for example, it will look like this: +The +deep_dup+ method returns deep copy of a given object. Normally, when you +dup+ an object that contains other objects, ruby does not +dup+ them. If you have an array with a string, for example, it will look like this: <ruby> array = ['string'] @@ -164,7 +164,7 @@ duplicate = array.dup duplicate.push 'another-string' -# object was duplicated, element added only to duplicate +# object was duplicated, so element was added only to duplicate array #=> ['string'] duplicate #=> ['string', 'another-string'] @@ -177,7 +177,7 @@ duplicate #=> ['foo', 'another-string'] As you can see, after duplicating +Array+ instance, we got another object, therefore we can modify it and the original object will stay unchanged. This is not true for array's elements, however. Since +dup+ does not make deep copy, the string inside array is still the same object. -If you need a deep copy of an object, you should use +deep_dup+ in such situation: +If you need a deep copy of an object, you should use +deep_dup+. Here is an example: <ruby> array = ['string'] @@ -189,7 +189,7 @@ array #=> ['string'] duplicate #=> ['foo'] </ruby> -If object is not duplicable +deep_dup+ will just return this object: +If object is not duplicable, +deep_dup+ will just return this object: <ruby> number = 1 @@ -201,9 +201,21 @@ NOTE: Defined in +active_support/core_ext/object/deep_dup.rb+. h4. +try+ -Sometimes you want to call a method provided the receiver object is not +nil+, which is something you usually check first. +try+ is like +Object#send+ except that it returns +nil+ if sent to +nil+. +When you want to call a method on an object only if it is not +nil+, the simplest way to achieve it is with conditional statements, adding unnecessary clutter. The alternative is to use +try+. +try+ is like +Object#send+ except that it returns +nil+ if sent to +nil+. -For instance, in this code from +ActiveRecord::ConnectionAdapters::AbstractAdapter+ +@logger+ could be +nil+, but you save the check and write in an optimistic style: +Here is an example: + +<ruby> +# without try +unless @number.nil? + @number.next +end + +# with try +@number.try(:next) +</ruby> + +Another example is this code from +ActiveRecord::ConnectionAdapters::AbstractAdapter+ where +@logger+ could be +nil+. You can see that the code uses +try+ and avoids an unnecessary check. <ruby> def log_info(sql, name, ms) @@ -245,7 +257,7 @@ NOTE: Defined in +active_support/core_ext/kernel/singleton_class.rb+. h4. +acts_like?(duck)+ -The method +acts_like+ provides a way to check whether some class acts like some other class based on a simple convention: a class that provides the same interface as +String+ defines +The method +acts_like?+ provides a way to check whether some class acts like some other class based on a simple convention: a class that provides the same interface as +String+ defines <ruby> def acts_like_string? @@ -1840,6 +1852,76 @@ date and time arithmetic. NOTE: Defined in +active_support/core_ext/numeric/time.rb+. +h4. Formatting + +Enables the formatting of numbers in a variety of ways. + +Produce a string representation of a number as a telephone number: +<ruby> +5551234.to_s(:phone) # => 555-1234 +1235551234.to_s(:phone) # => 123-555-1234 +1235551234.to_s(:phone, :area_code => true) # => (123) 555-1234 +1235551234.to_s(:phone, :delimiter => " ") # => 123 555 1234 +1235551234.to_s(:phone, :area_code => true, :extension => 555) # => (123) 555-1234 x 555 +1235551234.to_s(:phone, :country_code => 1) # => +1-123-555-1234 +</ruby> + +Produce a string representation of a number as currency: +<ruby> +1234567890.50.to_s(:currency) # => $1,234,567,890.50 +1234567890.506.to_s(:currency) # => $1,234,567,890.51 +1234567890.506.to_s(:currency, :precision => 3) # => $1,234,567,890.506 +</ruby> + +Produce a string representation of a number as a percentage: +<ruby> +100.to_s(:percentage) # => 100.000% +100.to_s(:percentage, :precision => 0) # => 100% +1000.to_s(:percentage, :delimiter => '.', :separator => ',') # => 1.000,000% +302.24398923423.to_s(:percentage, :precision => 5) # => 302.24399% +</ruby> + +Produce a string representation of a number in delimited form: +<ruby> +12345678.to_s(:delimited) # => 12,345,678 +12345678.05.to_s(:delimited) # => 12,345,678.05 +12345678.to_s(:delimited, :delimiter => ".") # => 12.345.678 +12345678.to_s(:delimited, :delimiter => ",") # => 12,345,678 +12345678.05.to_s(:delimited, :separator => " ") # => 12,345,678 05 +</ruby> + +Produce a string representation of a number rounded to a precision: +<ruby> +111.2345.to_s(:rounded) # => 111.235 +111.2345.to_s(:rounded, :precision => 2) # => 111.23 +13.to_s(:rounded, :precision => 5) # => 13.00000 +389.32314.to_s(:rounded, :precision => 0) # => 389 +111.2345.to_s(:rounded, :significant => true) # => 111 +</ruby> + +Produce a string representation of a number as a human-readable number of bytes: +<ruby> +123.to_s(:human_size) # => 123 Bytes +1234.to_s(:human_size) # => 1.21 KB +12345.to_s(:human_size) # => 12.1 KB +1234567.to_s(:human_size) # => 1.18 MB +1234567890.to_s(:human_size) # => 1.15 GB +1234567890123.to_s(:human_size) # => 1.12 TB +</ruby> + +Produce a string representation of a number in human-readable words: +<ruby> +123.to_s(:human) # => "123" +1234.to_s(:human) # => "1.23 Thousand" +12345.to_s(:human) # => "12.3 Thousand" +1234567.to_s(:human) # => "1.23 Million" +1234567890.to_s(:human) # => "1.23 Billion" +1234567890123.to_s(:human) # => "1.23 Trillion" +1234567890123456.to_s(:human) # => "1.23 Quadrillion" +</ruby> + +NOTE: Defined in +active_support/core_ext/numeric/formatting.rb+. + h3. Extensions to +Integer+ h4. +multiple_of?+ diff --git a/guides/source/active_support_instrumentation.textile b/guides/source/active_support_instrumentation.textile index 430549fba4..dcdd9d14f5 100644 --- a/guides/source/active_support_instrumentation.textile +++ b/guides/source/active_support_instrumentation.textile @@ -15,7 +15,7 @@ h3. Introduction to instrumentation The instrumentation API provided by ActiveSupport allows developers to provide hooks which other developers may hook into. There are several of these within the Rails framework, as described below in <TODO: link to section detailing each hook point>. With this API, developers can choose to be notified when certain events occur inside their application or another piece of Ruby code. -For example, there is a hook provided within Active Record that is called every time Active Record uses a SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken. +For example, there is a hook provided within Active Record that is called every time Active Record uses an SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken. You are even able to create your own events inside your application which you can later subscribe to. @@ -377,7 +377,7 @@ listen to any notification. The block receives the following arguments: # The name of the event -# Time when is started +# Time when it started # Time when it finished # An unique ID for this event # The payload (described in previous sections) diff --git a/guides/source/command_line.textile b/guides/source/command_line.textile index b656a0857a..19e42cea93 100644 --- a/guides/source/command_line.textile +++ b/guides/source/command_line.textile @@ -31,20 +31,21 @@ h4. +rails new+ The first thing we'll want to do is create a new Rails application by running the +rails new+ command after installing Rails. -TIP: You can install the rails gem by typing +gem install rails+, if you don't have it already. +INFO: You can install the rails gem by typing +gem install rails+, if you don't have it already. <shell> $ rails new commandsapp create create README.rdoc - create .gitignore create Rakefile create config.ru + create .gitignore create Gemfile create app ... create tmp/cache - create tmp/pids + ... + run bundle install </shell> Rails will set you up with what seems like a huge amount of stuff for such a tiny command! You've got the entire Rails directory structure now with all the code you need to run our simple application right out of the box. @@ -61,17 +62,17 @@ With no further work, +rails server+ will run our new shiny Rails app: $ cd commandsapp $ rails server => Booting WEBrick -=> Rails 3.1.0 application starting in development on http://0.0.0.0:3000 +=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server -[2010-04-18 03:20:33] INFO WEBrick 1.3.1 -[2010-04-18 03:20:33] INFO ruby 1.8.7 (2010-01-10) [x86_64-linux] -[2010-04-18 03:20:33] INFO WEBrick::HTTPServer#start: pid=26086 port=3000 +[2012-05-28 00:39:41] INFO WEBrick 1.3.1 +[2012-05-28 00:39:41] INFO ruby 1.9.2 (2011-02-18) [x86_64-darwin11.2.0] +[2012-05-28 00:39:41] INFO WEBrick::HTTPServer#start: pid=69680 port=3000 </shell> With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open "http://localhost:3000":http://localhost:3000, you will see a basic Rails app running. -You can also use the alias "s" to start the server: <tt>rails s</tt>. +INFO: You can also use the alias "s" to start the server: <tt>rails s</tt>. The server can be run on a different port using the +-p+ option. The default development environment can be changed using +-e+. @@ -85,7 +86,7 @@ h4. +rails generate+ The +rails generate+ command uses templates to create a whole lot of things. Running +rails generate+ by itself gives a list of available generators: -You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>. +INFO: You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>. <shell> $ rails generate @@ -97,6 +98,7 @@ Usage: rails generate GENERATOR [args] [options] Please choose a generator below. Rails: + assets controller generator ... @@ -118,23 +120,22 @@ Usage: rails generate controller NAME [action action] [options] ... ... +Description: + ... + + To create a controller within a module, specify the controller name as a + path like 'parent_module/controller_name'. + + ... + Example: - rails generate controller CreditCard open debit credit close + `rails generate controller CreditCard open debit credit close` Credit card controller with URLs like /credit_card/debit. - Controller: app/controllers/credit_card_controller.rb - Views: app/views/credit_card/debit.html.erb [...] - Helper: app/helpers/credit_card_helper.rb - Test: test/functional/credit_card_controller_test.rb - -Modules Example: - rails generate controller 'admin/credit_card' suspend late_fee - - Credit card admin controller with URLs like /admin/credit_card/suspend. - Controller: app/controllers/admin/credit_card_controller.rb - Views: app/views/admin/credit_card/debit.html.erb [...] - Helper: app/helpers/admin/credit_card_helper.rb - Test: test/functional/admin/credit_card_controller_test.rb + Controller: app/controllers/credit_card_controller.rb + Functional Test: test/functional/credit_card_controller_test.rb + Views: app/views/credit_card/debit.html.erb [...] + Helper: app/helpers/credit_card_helper.rb </shell> The controller generator is expecting parameters in the form of +generate controller ControllerName action1 action2+. Let's make a +Greetings+ controller with an action of *hello*, which will say something nice to us. @@ -153,10 +154,10 @@ $ rails generate controller Greetings hello invoke test_unit create test/unit/helpers/greetings_helper_test.rb invoke assets - create app/assets/javascripts/greetings.js - invoke css - create app/assets/stylesheets/greetings.css - + invoke coffee + create app/assets/javascripts/greetings.js.coffee + invoke scss + create app/assets/stylesheets/greetings.css.scss </shell> What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a javascript file and a stylesheet file. @@ -193,21 +194,19 @@ Rails comes with a generator for data models too. <shell> $ rails generate model -Usage: rails generate model NAME [field:type field:type] [options] +Usage: + rails generate model NAME [field[:type][:index] field[:type][:index]] [options] ... -Examples: - rails generate model account - - Model: app/models/account.rb - Test: test/unit/account_test.rb - Fixtures: test/fixtures/accounts.yml - Migration: db/migrate/XXX_add_accounts.rb +ActiveRecord options: + [--migration] # Indicates when to generate migration + # Default: true - rails generate model post title:string body:text published:boolean +... - Creates a Post model with a string title, text body, and published flag. +Description: + Create rails files for model generator. </shell> NOTE: For a list of available field types, refer to the "API documentation":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column for the column method for the +TableDefinition+ class. @@ -218,46 +217,47 @@ We will set up a simple resource called "HighScore" that will keep track of our <shell> $ rails generate scaffold HighScore game:string score:integer - exists app/models/ - exists app/controllers/ - exists app/helpers/ - create app/views/high_scores - create app/views/layouts/ - exists test/functional/ - create test/unit/ - create app/assets/stylesheets/ - create app/views/high_scores/index.html.erb - create app/views/high_scores/show.html.erb - create app/views/high_scores/new.html.erb - create app/views/high_scores/edit.html.erb - create app/views/layouts/high_scores.html.erb - create app/assets/stylesheets/scaffold.css.scss - create app/controllers/high_scores_controller.rb - create test/functional/high_scores_controller_test.rb - create app/helpers/high_scores_helper.rb - route resources :high_scores -dependency model - exists app/models/ - exists test/unit/ - create test/fixtures/ + invoke active_record + create db/migrate/20120528060026_create_high_scores.rb create app/models/high_score.rb - create test/unit/high_score_test.rb - create test/fixtures/high_scores.yml - exists db/migrate - create db/migrate/20100209025147_create_high_scores.rb + invoke test_unit + create test/unit/high_score_test.rb + create test/fixtures/high_scores.yml + route resources :high_scores + invoke scaffold_controller + create app/controllers/high_scores_controller.rb + invoke erb + create app/views/high_scores + create app/views/high_scores/index.html.erb + create app/views/high_scores/edit.html.erb + create app/views/high_scores/show.html.erb + create app/views/high_scores/new.html.erb + create app/views/high_scores/_form.html.erb + invoke test_unit + create test/functional/high_scores_controller_test.rb + invoke helper + create app/helpers/high_scores_helper.rb + invoke test_unit + create test/unit/helpers/high_scores_helper_test.rb + invoke assets + invoke coffee + create app/assets/javascripts/high_scores.js.coffee + invoke scss + create app/assets/stylesheets/high_scores.css.scss + invoke scss + create app/assets/stylesheets/scaffolds.css.scss </shell> The generator checks that there exist the directories for models, controllers, helpers, layouts, functional and unit tests, stylesheets, creates the views, controller, model and database migration for HighScore (creating the +high_scores+ table and fields), takes care of the route for the *resource*, and new tests for everything. -The migration requires that we *migrate*, that is, run some Ruby code (living in that +20100209025147_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while. +The migration requires that we *migrate*, that is, run some Ruby code (living in that +20120528060026_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while. <shell> $ rake db:migrate -(in /home/foobar/commandsapp) == CreateHighScores: migrating =============================================== -- create_table(:high_scores) - -> 0.0026s -== CreateHighScores: migrated (0.0028s) ====================================== + -> 0.0017s +== CreateHighScores: migrated (0.0019s) ====================================== </shell> INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions about code. In unit testing, we take a little part of code, say a method of a model, and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. We'll make one in a moment. @@ -274,19 +274,19 @@ h4. +rails console+ The +console+ command lets you interact with your Rails application from the command line. On the underside, +rails console+ uses IRB, so if you've ever used it, you'll be right at home. This is useful for testing out quick ideas with code and changing data server-side without touching the website. -You can also use the alias "c" to invoke the console: <tt>rails c</tt>. +INFO: You can also use the alias "c" to invoke the console: <tt>rails c</tt>. -You can specify the environment in which the +console+ command should operate using the +-e+ switch. +You can specify the environment in which the +console+ command should operate. <shell> -$ rails console -e staging +$ rails console staging </shell> If you wish to test out some code without changing any data, you can do that by invoking +rails console --sandbox+. <shell> $ rails console --sandbox -Loading development environment in sandbox (Rails 3.1.0) +Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit irb(main):001:0> </shell> @@ -295,7 +295,7 @@ h4. +rails dbconsole+ +rails dbconsole+ figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL, PostgreSQL, SQLite and SQLite3. -You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>. +INFO: You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>. h4. +rails runner+ @@ -305,7 +305,7 @@ h4. +rails runner+ $ rails runner "Model.long_running_method" </shell> -You can also use the alias "r" to invoke the runner: <tt>rails r</tt>. +INFO: You can also use the alias "r" to invoke the runner: <tt>rails r</tt>. You can specify the environment in which the +runner+ command should operate using the +-e+ switch. @@ -317,31 +317,25 @@ h4. +rails destroy+ Think of +destroy+ as the opposite of +generate+. It'll figure out what generate did, and undo it. -You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>. +INFO: You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>. <shell> $ rails generate model Oops - exists app/models/ - exists test/unit/ - exists test/fixtures/ - create app/models/oops.rb - create test/unit/oops_test.rb - create test/fixtures/oops.yml - exists db/migrate - create db/migrate/20081221040817_create_oops.rb + invoke active_record + create db/migrate/20120528062523_create_oops.rb + create app/models/oops.rb + invoke test_unit + create test/unit/oops_test.rb + create test/fixtures/oops.yml +</shell> +<shell> $ rails destroy model Oops - notempty db/migrate - notempty db - rm db/migrate/20081221040817_create_oops.rb - rm test/fixtures/oops.yml - rm test/unit/oops_test.rb - rm app/models/oops.rb - notempty test/fixtures - notempty test - notempty test/unit - notempty test - notempty app/models - notempty app + invoke active_record + remove db/migrate/20120528062523_create_oops.rb + remove app/models/oops.rb + invoke test_unit + remove test/unit/oops_test.rb + remove test/fixtures/oops.yml </shell> h3. Rake @@ -352,16 +346,16 @@ You can get a list of Rake tasks available to you, which will often depend on yo <shell> $ rake --tasks -(in /home/foobar/commandsapp) -rake db:abort_if_pending_migrations # Raises an error if there are pending migrations -rake db:charset # Retrieves the charset for the current environment's database -rake db:collation # Retrieves the collation for the current environment's database -rake db:create # Create the database defined in config/database.yml for the current Rails.env +rake about # List versions of all Rails frameworks and the environment +rake assets:clean # Remove compiled assets +rake assets:precompile # Compile all the assets named in config.assets.precompile +rake db:create # Create the database from config/database.yml for the current Rails.env ... +rake log:clear # Truncates all *.log files in log/ to zero bytes +rake middleware # Prints out your Rack middleware stack ... -rake tmp:pids:clear # Clears all files in tmp/pids -rake tmp:sessions:clear # Clears all files in tmp/sessions -rake tmp:sockets:clear # Clears all files in tmp/sockets +rake tmp:clear # Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear) +rake tmp:create # Creates tmp directories for sessions, cache, sockets, and pids </shell> h4. +about+ diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile index 72cdea885f..acf75d41cd 100644 --- a/guides/source/contributing_to_ruby_on_rails.textile +++ b/guides/source/contributing_to_ruby_on_rails.textile @@ -412,6 +412,42 @@ Push to your remote: $ git push mine my_new_branch </shell> +You might have cloned your forked repository into your machine and might want to add the original Rails repository as a remote instead, if that's the case here's what you have to do. + +In the directory you cloned your fork: + +<shell> +$ git remote add rails git://github.com/rails/rails.git +</shell> + +Download new commits and branches from the official repository: + +<shell> +$ git fetch rails +</shell> + +Merge the new content: + +<shell> +$ git checkout master +$ git rebase rails/master +</shell> + +Update your fork: + +<shell> +$ git push origin master +</shell> + +If you want to update another branches: + +<shell> +$ git checkout branch_name +$ git rebase rails/branch_name +$ git push origin branch_name +</shell> + + h4. Issue a Pull Request Navigate to the Rails repository you just pushed to (e.g. https://github.com/your-user-name/rails) and press "Pull Request" in the upper right hand corner. diff --git a/guides/source/engines.textile b/guides/source/engines.textile index c35305a822..86e7254201 100644 --- a/guides/source/engines.textile +++ b/guides/source/engines.textile @@ -36,6 +36,12 @@ To generate an engine with Rails 3.1, you will need to run the plugin generator $ rails plugin new blorgh --full --mountable </shell> +The full list of options for the plugin generator may be seen by typing: + +<shell> +$ rails plugin --help +</shell> + The +--full+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file. The +--mountable+ option tells the generator to mount the engine inside the dummy testing application located at +test/dummy+ inside the engine. It does this by placing this line in to the dummy application's +config/routes.rb+ file, located at +test/dummy/config/routes.rb+ inside the engine: diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index c129aeb2e1..f25e0c0200 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -75,7 +75,7 @@ By following along with this guide, you'll create a Rails project called (very) simple weblog. Before you can start building the application, you need to make sure that you have Rails itself installed. -TIP: The examples below use # and $ to denote terminal prompts. If you are using Windows, your prompt will look something like c:\source_code> +TIP: The examples below use # and $ to denote superuser and regular user terminal prompts respectively in a UNIX-like OS. If you are using Windows, your prompt will look something like c:\source_code> h4. Installing Rails @@ -108,7 +108,7 @@ To use this generator, open a terminal, navigate to a directory where you have r $ rails new blog </shell> -This will create a Rails application called Blog in a directory called blog. +This will create a Rails application called Blog in a directory called blog and install the gem dependencies that are already mentioned in +Gemfile+ using +bundle install+. TIP: You can see all of the command line options that the Rails application builder accepts by running +rails new -h+. @@ -138,7 +138,7 @@ application. Most of the work in this tutorial will happen in the +app/+ folder, |README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| |script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.| |test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html| -|tmp/|Temporary files| +|tmp/|Temporary files (like cache, pid and session files)| |vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems and the Rails source code (if you optionally install it into your project).| h3. Hello, Rails! @@ -177,7 +177,28 @@ To create a new controller, you will need to run the "controller" generator and $ rails generate controller welcome index </shell> -Rails will create several files for you. Most important of these are of course the controller, located at +app/controllers/welcome_controller.rb+ and the view, located at +app/views/welcome/index.html.erb+. +Rails will create several files and a route for you. + +<shell> +create app/controllers/welcome_controller.rb + route get "welcome/index" +invoke erb +create app/views/welcome +create app/views/welcome/index.html.erb +invoke test_unit +create test/functional/welcome_controller_test.rb +invoke helper +create app/helpers/welcome_helper.rb +invoke test_unit +create test/unit/helpers/welcome_helper_test.rb +invoke assets +invoke coffee +create app/assets/javascripts/welcome.js.coffee +invoke scss +create app/assets/stylesheets/welcome.css.scss +</shell> + +Most important of these are of course the controller, located at +app/controllers/welcome_controller.rb+ and the view, located at +app/views/welcome/index.html.erb+. Open the +app/views/welcome/index.html.erb+ file in your text editor and edit it to contain a single line of code: @@ -195,18 +216,27 @@ You need to do this because Rails will serve any static file in the +public+ dir Next, you have to tell Rails where your actual home page is located. -Open the file +config/routes.rb+ in your editor. This is your application's _routing file_ which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. This file contains many sample routes on commented lines, and one of them actually shows you how to connect the root of your site to a specific controller and action. Find the line beginning with +root :to+ and uncomment it. It should look something like the following: +Open the file +config/routes.rb+ in your editor. <ruby> Blog::Application.routes.draw do - - #... + get "welcome/index" + + # The priority is based upon order of creation: + # first created -> highest priority. + # ... # You can have the root of your site routed with "root" # just remember to delete public/index.html. - root :to => "welcome#index" + # root :to => "welcome#index" +</ruby> + +This is your application's _routing file_ which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. This file contains many sample routes on commented lines, and one of them actually shows you how to connect the root of your site to a specific controller and action. Find the line beginning with +root :to+ and uncomment it. It should look something like the following: + +<ruby> +root :to => "welcome#index" </ruby> -The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+). +The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action and +get "welcome/index"+ tells Rails to map requests to "http://localhost:3000/welcome/index":http://localhost:3000/welcome/index to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+). If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see the +Hello, Rails!+ message you put into +app/views/welcome/index.html.erb+, indicating that this new route is indeed going to +WelcomeController+'s +index+ action and is rendering the view correctly. @@ -500,7 +530,7 @@ database columns. In the first line we do just that (remember that +params[:post]+ contains the attributes we're interested in). Then, +@post.save+ is responsible for saving the model in the database. Finally, we redirect the user to the +show+ action, -wich we'll define later. +which we'll define later. TIP: As we'll see later, +@post.save+ returns a boolean indicating wherever the model was saved or not. @@ -610,7 +640,7 @@ The +link_to+ method is one of Rails' built-in view helpers. It creates a hyperlink based on text to display and where to go - in this case, to the path for posts. -Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag: +Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag: <erb> <%= link_to 'New post', :action => :new %> @@ -1129,7 +1159,7 @@ together. Here we're using +link_to+ in a different way. We wrap the +:action+ and +:id+ attributes in a hash so that we can pass those two keys in first as one argument, and then the final two keys as another argument. The +:method+ and +:confirm+ -options are used as html5 attributes so that when the click is linked, +options are used as HTML5 attributes so that when the link is clicked, Rails will first show a confirm dialog to the user, and then submit the link with method +delete+. This is done via the JavaScript file +jquery_ujs+ which is automatically included into your application's layout diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 12b2eb7458..48d4373afe 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -57,7 +57,7 @@ else end </ruby> -The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see thisin use in +railties/lib/rails/script_rails_loader+. +The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see this in use in +railties/lib/rails/script_rails_loader+. <ruby> require 'pathname' @@ -157,11 +157,11 @@ The gems that a Rails 4 application depends on are as follows: TODO: change these when the Rails 4 release is near. * abstract (1.0.0) -* actionmailer (3.1.0.beta) -* actionpack (3.1.0.beta) -* activemodel (3.1.0.beta) -* activerecord (3.1.0.beta) -* activesupport (3.1.0.beta) +* actionmailer (4.0.0.beta) +* actionpack (4.0.0.beta) +* activemodel (4.0.0.beta) +* activerecord (4.0.0.beta) +* activesupport (4.0.0.beta) * arel (2.0.7) * builder (3.0.0) * bundler (1.0.6) @@ -174,8 +174,8 @@ TODO: change these when the Rails 4 release is near. * rack-cache (0.5.3) * rack-mount (0.6.13) * rack-test (0.5.6) -* rails (3.1.0.beta) -* railties (3.1.0.beta) +* rails (4.0.0.beta) +* railties (4.0.0.beta) * rake (0.8.7) * sqlite3-ruby (1.3.2) * thor (0.14.6) @@ -191,6 +191,7 @@ ARGV << '--help' if ARGV.empty? aliases = { "g" => "generate", + "d" => "destroy", "c" => "console", "s" => "server", "db" => "dbconsole", @@ -531,6 +532,7 @@ require "rails" action_controller action_mailer rails/test_unit + sprockets/rails ).each do |framework| begin require "#{framework}/railtie" @@ -543,13 +545,19 @@ First off the line is the +rails+ require itself. h4. +railties/lib/rails.rb+ -This file is responsible for the initial definition of the +Rails+ module and, rather than defining the autoloads like +ActiveSupport+, +ActionDispatch+ and so on, it actually defines other functionality. Such as the +root+, +env+ and +application+ methods which are extremely useful in Rails 3 applications. +This file is responsible for the initial definition of the +Rails+ +module and, rather than defining the autoloads like +ActiveSupport+, ++ActionDispatch+ and so on, it actually defines other functionality. +Such as the +root+, +env+ and +application+ methods which are extremely +useful in Rails 4 applications. However, before all that takes place the +rails/ruby_version_check+ file is required first. h4. +railties/lib/rails/ruby_version_check.rb+ -This file simply checks if the Ruby version is less than 1.8.7 or is 1.9.1 and raises an error if that is the case. Rails 3 simply will not run on earlier versions of Ruby than 1.8.7 or 1.9.1. +This file simply checks if the Ruby version is less than 1.9.3 and +raises an error if that is the case. Rails 4 simply will not run on +earlier versions of Ruby. NOTE: You should always endeavor to run the latest version of Ruby with your Rails applications. The benefits are many, including security fixes and the like, and very often there is a speed increase associated with it. The caveat is that you could have code that potentially breaks on the latest version, which should be fixed to work on the latest version rather than kept around as an excuse not to upgrade. @@ -565,35 +573,28 @@ end These methods can be used to silence STDERR responses and the +silence_stream+ allows you to also silence other streams. Additionally, this mixin allows you to suppress exceptions and capture streams. For more information see the "Silencing Warnings, Streams, and Exceptions":active_support_core_extensions.html#silencing-warnings-streams-and-exceptions section from the Active Support Core Extensions Guide. -h4. +active_support/core_ext/logger.rb+ +h4. +active_support/core_ext/array/extract_options.rb+ -The next file that is required is another Active Support core extension, this time to the +Logger+ class. This begins by defining the +around_[level]+ helpers for the +Logger+ class as well as other methods such as a +datetime_format+ getter and setter for the +formatter+ object tied to a +Logger+ object. - -For more information see the "Extensions to Logger":active_support_core_extensions.html#extensions-to-logger section from the Active Support Core Extensions Guide. +The next file that is required is another Active Support core extension, +this time to the +Array+ and +Hash+ classes. This file defines an ++extract_options!+ method which Rails uses to extract options from +parameters. h4. +railties/lib/rails/application.rb+ -The next file required by +railties/lib/rails.rb+ is +application.rb+. This file defines the +Rails::Application+ constant which the application's class defined in +config/application.rb+ in a standard Rails application depends on. Before the +Rails::Application+ class is defined however, there's some other files that get required first. - -The first of these is +active_support/core_ext/hash/reverse_merge+ which can be "read about in the Active Support Core Extensions guide":active_support_core_extensions.html#merging under the "Merging" section. - -h4. +active_support/file_update_checker.rb+ - -The +ActiveSupport::FileUpdateChecker+ class defined within this file is responsible for checking if a file has been updated since it was last checked. This is used for monitoring the routes file for changes during development environment runs. +The next file required by +railties/lib/rails.rb+ is +application.rb+. +This file defines the +Rails::Application+ constant which the +application's class defined in +config/application.rb+ in a standard +Rails application depends on. -h4. +railties/lib/rails/plugin.rb+ - -This file defines +Rails::Plugin+ which inherits from +Rails::Engine+. Unlike +Rails::Engine+ and +Rails::Railtie+ however, this class is not designed to be inherited from. Instead, this is used simply for loading plugins from within an application and an engine. - -This file begins by requiring +rails/engine.rb+ - -h4. +railties/lib/rails/engine.rb+ +Before the +Rails::Application+ class is +defined however, +rails/engine+ is also loaded, which is responsible for +handling the behavior and definitions of Rails engines. -The +rails/engine.rb+ file defines the +Rails::Engine+ class which inherits from +Rails::Railtie+. The +Rails::Engine+ class defines much of the functionality found within a standard application class such as the +routes+ and +config+ methods. +TIP: You can read more about engines in the "Getting Started with Engines":engines.html guide. -The "API documentation":http://api.rubyonrails.org/classes/Rails/Engine.html for +Rails::Engine+ explains the function of this class pretty well. - -This file's first line requires +rails/railtie.rb+. +Among other things, Rails Engine is also responsible for loading the +Railtie class. h4. +railties/lib/rails/railtie.rb+ @@ -655,7 +656,7 @@ h4. +activesupport/lib/active_support/deprecation/proxy_wrappers.rb+ +proxy_wrappers.rb+ defines deprecation wrappers for methods, instance variables and constants. Previously, this was used for the +RAILS_ENV+ and +RAILS_ROOT+ constants for 3.0 but since then these constants have been removed. The deprecation message that would be raised from these would be something like: <plain> - BadConstant is deprecated! Use GoodConstant instead. +BadConstant is deprecated! Use GoodConstant instead. </plain> h4. +active_support/ordered_options+ @@ -664,7 +665,30 @@ This file is the next file required from +rails/configuration.rb+ is the file th The next file required is +active_support/core_ext/hash/deep_dup+ which is covered in "Active Support Core Extensions guide":active_support_core_extensions.html#deep_dup -The file that is required next from is +rails/paths+ +h4. +active_support/core_ext/object+ + +This file is responsible for requiring many more Active Support core extensions: + +<ruby> +require 'active_support/core_ext/object/acts_like' +require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/object/duplicable' +require 'active_support/core_ext/object/deep_dup' +require 'active_support/core_ext/object/try' +require 'active_support/core_ext/object/inclusion' + +require 'active_support/core_ext/object/conversions' +require 'active_support/core_ext/object/instance_variables' + +require 'active_support/core_ext/object/to_json' +require 'active_support/core_ext/object/to_param' +require 'active_support/core_ext/object/to_query' +require 'active_support/core_ext/object/with_options' +</ruby> + +The Rails API documentation covers them in great detail, so we're not going to explain each of them. + +The file that is required next from +rails/configuration+ is +rails/paths+. h4. +railties/lib/rails/paths.rb+ @@ -680,7 +704,6 @@ module Rails autoload :Debugger, "rails/rack/debugger" autoload :Logger, "rails/rack/logger" autoload :LogTailer, "rails/rack/log_tailer" - autoload :Static, "rails/rack/static" end end </ruby> @@ -706,9 +729,23 @@ h4. +active_support/inflections+ This file references the +ActiveSupport::Inflector+ constant which isn't loaded by this point. But there were autoloads set up in +activesupport/lib/active_support.rb+ which will load the file which loads this constant and so then it will be defined. Then this file defines pluralization and singularization rules for words in Rails. This is how Rails knows how to pluralize "tomato" to "tomatoes". +<ruby> +inflect.irregular('zombie', 'zombies') +</ruby> + h4. +activesupport/lib/active_support/inflector/transliterate.rb+ -In this file is where the "+transliterate+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate and +parameterize+:http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize methods are defined. The documentation for both of these methods is very much worth reading. +This is the file that defines the "+transliterate+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate and "+parameterize+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize methods. + +h4. +active_support/core_ext/module/introspection+ + +The next file loaded by +rails/railtie+ is the introspection core +extension, which extends +Module+ with methods like +parent_name+, +parent+ and ++parents+. + +h4. +active_support/core_ext/module/delegation+ + +The final file loaded by +rails/railtie+ is the delegation core extension, which defines the "+delegate+":http://api.rubyonrails.org/classes/Module.html#method-i-delegate method. h4. Back to +railties/lib/rails/railtie.rb+ @@ -888,7 +925,7 @@ The +initializers_chain+ method referenced in the +initializers_for+ method is d <ruby> def initializers_chain initializers = Collection.new - ancestors.reverse_each do | klass | + ancestors.reverse_each do |klass| next unless klass.respond_to?(:initializers) initializers = initializers + klass.initializers end @@ -951,46 +988,35 @@ This file defines the +ActiveSupport::Railtie+ constant which like the +I18n::Ra Then this Railtie sets up three more initializers: -* +active_support.initialize_whiny_nils+ * +active_support.deprecation_behavior+ * +active_support.initialize_time_zone+ +* +active_support.set_configs+ We will cover what each of these initializers do when they run. Once the +active_support/railtie+ file has finished loading the next file required from +railties/lib/rails.rb+ is the +action_dispatch/railtie+. -h4. +activesupport/lib/action_dispatch/railtie.rb+ +h4. +actionpack/lib/action_dispatch/railtie.rb+ This file defines the +ActionDispatch::Railtie+ class, but not before requiring +action_dispatch+. -h4. +activesupport/lib/action_dispatch.rb+ - -This file attempts to locate the +active_support+ and +active_model+ libraries by looking a couple of directories back from the current file and then adds the +active_support+ and +active_model+ +lib+ directories to the load path, but only if they aren't already, which they are. - -<ruby> -activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__) -$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) - -activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__) -$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path) -</ruby> - -In effect, these lines only define the +activesupport_path+ and +activemodel_path+ variables and nothing more. +h4. +actionpack/lib/action_dispatch.rb+ -The next two requires in this file are already done, so they are not run: +This file starts off with the following requires: <ruby> require 'active_support' require 'active_support/dependencies/autoload' +require 'active_support/core_ext/module/attribute_accessors' </ruby> -The following require is to +action_pack+ (+activesupport/lib/action_pack.rb+) which has a 22-line copyright notice at the top of it and ends in a simple require to +action_pack/version+. This file, like other +version.rb+ files before it, defines the +ActionPack::VERSION+ constant: +The following require is to +action_pack+ (+actionpack/lib/action_pack.rb+) which contains a simple require to +action_pack/version+. This file, like other +version.rb+ files before it, defines the +ActionPack::VERSION+ constant: <ruby> module ActionPack module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1008,8 +1034,8 @@ This file makes a require to +active_model/version+ which defines the version fo <ruby> module ActiveModel module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1046,7 +1072,7 @@ Once it has finished loading, the +I18n.load_path+ method is used to add the +ac The loading of this file finishes the loading of +active_model+ and so we go back to +action_dispatch+. -h4. Back to +activesupport/lib/action_dispatch.rb+ +h4. Back to +actionpack/lib/action_dispatch.rb+ The remainder of this file requires the +rack+ file from the Rack gem which defines the +Rack+ module. After +rack+, there's autoloads defined for the +Rack+, +ActionDispatch+, +ActionDispatch::Http+, +ActionDispatch::Session+. A new method called +autoload_under+ is used here, and this simply prefixes the files where the modules are autoloaded from with the path specified. For example here: @@ -1060,7 +1086,7 @@ The +Assertions+ module is in the +action_dispatch/testing+ folder rather than s Finally, this file defines a top-level autoload, the +Mime+ constant. -h4. Back to +activesupport/lib/action_dispatch/railtie.rb+ +h4. Back to +actionpack/lib/action_dispatch/railtie.rb+ After +action_dispatch+ is required in this file, the +ActionDispatch::Railtie+ class is defined and is yet another class that inherits from +Rails::Railtie+. This class defines some initial configuration option defaults for +config.action_dispatch+ before setting up a single initializer called +action_dispatch.configure+. @@ -1082,22 +1108,21 @@ h4. +activerecord/lib/active_record.rb+ This file begins by detecting if the +lib+ directories of +active_support+ and +active_model+ are not in the load path and if they aren't then adds them. As we saw back in +action_dispatch.rb+, these directories are already there. -The first three requires have already been done by other files and so aren't loaded here, but the 4th require, the one to +arel+ will require the file provided by the Arel gem, which defines the +Arel+ module. +The first couple of requires have already been done by other files and so aren't loaded here, but the next one to +arel+ will require the file provided by the Arel gem, which defines the +Arel+ module. <ruby> require 'active_support' -require 'active_support/i18n' require 'active_model' require 'arel' </ruby> -The 5th require in this file is one to +active_record/version+ which defines the +ActiveRecord::VERSION+ constant: +The file required next is +active_record/version+ which defines the +ActiveRecord::VERSION+ constant: <ruby> module ActiveRecord module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1121,7 +1146,9 @@ This will set the engine for +Arel::Table+ to be +ActiveRecord::Base+. The file then finishes with this line: <ruby> -I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' +ActiveSupport.on_load(:i18n) do + I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' +end </ruby> This will add the translations from +activerecord/lib/active_record/locale/en.yml+ to the load path for +I18n+, with this file being parsed when all the translations are loaded. diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile index 52dba76e68..342b5a4d57 100644 --- a/guides/source/migrations.textile +++ b/guides/source/migrations.textile @@ -8,8 +8,7 @@ production machines next time you deploy. Active Record tracks which migrations have already been run so all you have to do is update your source and run +rake db:migrate+. Active Record will work out -which migrations should be run. It will also update your +db/schema.rb+ file to -match the structure of your database. +which migrations should be run. Active Record will also update your +db/schema.rb+ file to match the up-to-date structure of your database. Migrations also allow you to describe these transformations using Ruby. The great thing about this is that (like most of Active Record's functionality) it diff --git a/guides/source/rails_on_rack.textile b/guides/source/rails_on_rack.textile index d8910cf1d0..3a7c392508 100644 --- a/guides/source/rails_on_rack.textile +++ b/guides/source/rails_on_rack.textile @@ -23,29 +23,49 @@ h3. Rails on Rack h4. Rails Application's Rack Object -<tt>ActionController::Dispatcher.new</tt> is the primary Rack application object of a Rails application. Any Rack compliant web server should be using +ActionController::Dispatcher.new+ object to serve a Rails application. +<tt>ApplicationName::Application</tt> is the primary Rack application object of a Rails application. Any Rack compliant web server should be using +ApplicationName::Application+ object to serve a Rails application. h4. +rails server+ -<tt>rails server</tt> does the basic job of creating a +Rack::Builder+ object and starting the webserver. This is Rails' equivalent of Rack's +rackup+ script. +<tt>rails server</tt> does the basic job of creating a +Rack::Server+ object and starting the webserver. -Here's how +rails server+ creates an instance of +Rack::Builder+ +Here's how +rails server+ creates an instance of +Rack::Server+ <ruby> -app = Rack::Builder.new { - use Rails::Rack::LogTailer unless options[:detach] - use Rails::Rack::Debugger if options[:debugger] - use ActionDispatch::Static - run ActionController::Dispatcher.new -}.to_app +Rails::Server.new.tap { |server| + require APP_PATH + Dir.chdir(Rails.application.root) + server.start +} </ruby> -Middlewares used in the code above are primarily useful only in the development environment. The following table explains their usage: +The +Rails::Server+ inherits from +Rack::Server+ and calls the +Rack::Server#start+ method this way: + +<ruby> +class Server < ::Rack::Server + def start + ... + super + end +end +</ruby> + +Here's how it loads the middlewares: + +<ruby> +def middleware + middlewares = [] + middlewares << [Rails::Rack::Debugger] if options[:debugger] + middlewares << [::Rack::ContentLength] + Hash.new(middlewares) +end +</ruby> + ++Rails::Rack::Debugger+ is primarily useful only in the development environment. The following table explains the usage of the loaded middlewares: |_.Middleware|_.Purpose| -|+Rails::Rack::LogTailer+|Appends log file output to console| -|+ActionDispatch::Static+|Serves static files inside +Rails.root/public+ directory| |+Rails::Rack::Debugger+|Starts Debugger| +|+Rack::ContentLength+|Counts the number of bytes in the response and set the HTTP Content-Length header| h4. +rackup+ @@ -55,9 +75,9 @@ To use +rackup+ instead of Rails' +rails server+, you can put the following insi # Rails.root/config.ru require "config/environment" -use Rails::Rack::LogTailer -use ActionDispatch::Static -run ActionController::Dispatcher.new +use Rack::Debugger +use Rack::ContentLength +run ApplicationName::Application </ruby> And start the server: @@ -72,11 +92,11 @@ To find out more about different +rackup+ options: $ rackup --help </shell> -h3. Action Controller Middleware Stack +h3. Action Dispatcher Middleware Stack -Many of Action Controller's internal components are implemented as Rack middlewares. +ActionController::Dispatcher+ uses +ActionController::MiddlewareStack+ to combine various internal and external middlewares to form a complete Rails Rack application. +Many of Action Dispatchers's internal components are implemented as Rack middlewares. +Rails::Application+ uses +ActionDispatch::MiddlewareStack+ to combine various internal and external middlewares to form a complete Rails Rack application. -NOTE: +ActionController::MiddlewareStack+ is Rails' equivalent of +Rack::Builder+, but built for better flexibility and more features to meet Rails' requirements. +NOTE: +ActionDispatch::MiddlewareStack+ is Rails' equivalent of +Rack::Builder+, but built for better flexibility and more features to meet Rails' requirements. h4. Inspecting Middleware Stack @@ -111,7 +131,7 @@ use ActionDispatch::Head use Rack::ConditionalGet use Rack::ETag use ActionDispatch::BestStandardsSupport -run Blog::Application.routes +run ApplicationName::Application.routes </ruby> Purpose of each of this middlewares is explained in the "Internal Middlewares":#internal-middleware-stack section. @@ -172,7 +192,7 @@ use ActionDispatch::Static use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8> use Rack::Runtime ... -run Myapp::Application.routes +run Blog::Application.routes </shell> h4. Internal Middleware Stack @@ -264,7 +284,7 @@ config.middleware.clear <ruby> # config.ru use MyOwnStackFromScratch -run ActionController::Dispatcher.new +run ApplicationName::Application </ruby> h3. Resources diff --git a/guides/source/routing.textile b/guides/source/routing.textile index 4a50edbb15..7941e655bb 100644 --- a/guides/source/routing.textile +++ b/guides/source/routing.textile @@ -395,7 +395,7 @@ NOTE: You can't use +:namespace+ or +:module+ with a +:controller+ path segment. get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/ </ruby> -TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment add a constraint which overrides this - for example +:id+ => /[^\/]+/ allows anything except a slash. +TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, +:id+ => /[^\/]+/ allows anything except a slash. h4. Static Segments @@ -445,6 +445,14 @@ get 'exit' => 'sessions#destroy', :as => :logout This will create +logout_path+ and +logout_url+ as named helpers in your application. Calling +logout_path+ will return +/exit+ +You can also use this to override routing methods defined by resources, like this: + +<ruby> +get ':username', :to => "users#show", :as => :user +</ruby> + +This will define a +user_path+ method that will be available in controllers, helpers and views that will go to a route such as +/bob+. Inside the +show+ action of +UsersController+, +params[:username]+ will contain the username for the user. Change +:username+ in the route definition if you do not want your parameter name to be +:username+. + h4. HTTP Verb Constraints In general, you should use the +get+, +post+, +put+ and +delete+ methods to constrain a route to a particular verb. You can use the +match+ method with the +:via+ option to match multiple verbs at once: @@ -851,9 +859,11 @@ h3. Inspecting and Testing Routes Rails offers facilities for inspecting and testing your routes. -h4. Seeing Existing Routes with +rake+ +h4. Seeing Existing Routes + +To get a complete list of the available routes in your application, visit +http://localhost:3000/rails/info/routes+ in your browser while your server is running in the *development* environment. You can also execute the +rake routes+ command in your terminal to produce the same output. -If you want a complete list of all of the available routes in your application, run +rake routes+ command. This will print all of your routes, in the same order that they appear in +routes.rb+. For each route, you'll see: +Both methods will list all of your routes, in the same order that they appear in +routes.rb+. For each route, you'll see: * The route name (if any) * The HTTP verb used (if the route doesn't respond to all verbs) diff --git a/guides/source/ruby_on_rails_guides_guidelines.textile b/guides/source/ruby_on_rails_guides_guidelines.textile index f3e934d38c..dd209b61d6 100644 --- a/guides/source/ruby_on_rails_guides_guidelines.textile +++ b/guides/source/ruby_on_rails_guides_guidelines.textile @@ -47,7 +47,13 @@ h4. Generation To generate all the guides, just +cd+ into the *+guides+* directory and execute: <plain> -bundle exec rake generate_guides +bundle exec rake guides:generate +</plain> + +or + +<plain> +bundle exec rake guides:generate:html </plain> (You may need to run +bundle install+ first to install the required gems.) @@ -56,7 +62,7 @@ To process +my_guide.textile+ and nothing else use the +ONLY+ environment variab <plain> touch my_guide.textile -bundle exec rake generate_guides ONLY=my_guide +bundle exec rake guides:generate ONLY=my_guide </plain> By default, guides that have not been modified are not processed, so +ONLY+ is rarely needed in practice. @@ -68,7 +74,13 @@ It is also recommended that you work with +WARNINGS=1+. This detects duplicate I If you want to generate guides in a language other than English, you can keep them in a separate directory under +source+ (eg. <tt>source/es</tt>) and use the +GUIDES_LANGUAGE+ environment variable: <plain> -bundle exec rake generate_guides GUIDES_LANGUAGE=es +bundle exec rake guides:generate GUIDES_LANGUAGE=es +</plain> + +If you want to see all the environment variables you can use to configure the generation script just run: + +<plain> +rake </plain> h4. Validation @@ -76,7 +88,7 @@ h4. Validation Please validate the generated HTML with: <plain> -bundle exec rake validate_guides +bundle exec rake guides:validate </plain> Particularly, titles get an ID generated from their content and this often leads to duplicates. Please set +WARNINGS=1+ when generating guides to detect them. The warning messages suggest a solution. @@ -85,8 +97,8 @@ h3. Kindle Guides h4(#generation-kindle). Generation -To generate guides for the Kindle, you need to provide +KINDLE=1+ as an environment variable: +To generate guides for the Kindle, use the following rake task: <plain> -KINDLE=1 bundle exec rake generate_guides +bundle exec rake guides:generate:kindle </plain> diff --git a/guides/source/security.textile b/guides/source/security.textile index ac55d60368..0931dd6393 100644 --- a/guides/source/security.textile +++ b/guides/source/security.textile @@ -30,7 +30,7 @@ A good place to start looking at security is with sessions, which can be vulnera h4. What are Sessions? --- _HTTP is a stateless protocol. Sessions make it stateful._ +NOTE: _HTTP is a stateless protocol. Sessions make it stateful._ Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request. Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application. @@ -44,13 +44,13 @@ User.find(session[:user_id]) h4. Session id --- _The session id is a 32 byte long MD5 hash value._ +NOTE: _The session id is a 32 byte long MD5 hash value._ A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date. h4. Session Hijacking --- _Stealing a user's session id lets an attacker use the web application in the victim's name._ +WARNING: _Stealing a user's session id lets an attacker use the web application in the victim's name._ Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session. @@ -72,7 +72,7 @@ The main objective of most attackers is to make money. The underground prices fo h4. Session Guidelines --- _Here are some general guidelines on sessions._ +Here are some general guidelines on sessions. * _(highlight)Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below). This will also be a good idea, if you modify the structure of an object and old versions of it are still in some user's cookies. With server-side session storages you can clear out the sessions, but with client-side storages, this is hard to mitigate. @@ -81,7 +81,7 @@ This will also be a good idea, if you modify the structure of an object and old h4. Session Storage --- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecord::SessionStore and ActionDispatch::Session::CookieStore._ +NOTE: _Rails provides several storage mechanisms for the session hashes. The most important are +ActiveRecord::SessionStore+ and +ActionDispatch::Session::CookieStore+._ There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecord::SessionStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecord::SessionStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. @@ -104,7 +104,7 @@ There are, however, derivatives of CookieStore which encrypt the session hash, s h4. Replay Attacks for CookieStore Sessions --- _Another sort of attack you have to be aware of when using CookieStore is the replay attack._ +TIP: _Another sort of attack you have to be aware of when using +CookieStore+ is the replay attack._ It works like this: @@ -120,7 +120,7 @@ The best _(highlight)solution against it is not to store this kind of data in a h4. Session Fixation --- _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._ +NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._ !images/session_fixation.png(Session fixation)! @@ -135,7 +135,7 @@ This attack focuses on fixing a user's session id known to the attacker, and for h4. Session Fixation – Countermeasures --- _One line of code will protect you from session fixation._ +TIP: _One line of code will protect you from session fixation._ The most effective countermeasure is to _(highlight)issue a new session identifier_ and declare the old one invalid after a successful login. That way, an attacker cannot use the fixed session identifier. This is a good countermeasure against session hijacking, as well. Here is how to create a new session in Rails: @@ -149,7 +149,7 @@ Another countermeasure is to _(highlight)save user-specific properties in the se h4. Session Expiry --- _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._ +NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._ One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _(highlight)expire sessions in a database table_. Call +Session.sweep("20 minutes")+ to expire sessions that were used longer than 20 minutes ago. @@ -174,7 +174,7 @@ delete_all "updated_at < '#{time.ago.to_s(:db)}' OR h3. Cross-Site Request Forgery (CSRF) --- _This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands._ +This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands. !images/csrf.png! @@ -193,7 +193,7 @@ CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) -- less t h4. CSRF Countermeasures --- _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._ +NOTE: _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._ The HTTP protocol basically provides two main types of requests - GET and POST (and more, but they are not supported by most browsers). The World Wide Web Consortium (W3C) provides a checklist for choosing HTTP GET or POST: @@ -236,6 +236,17 @@ protect_from_forgery :secret => "123456789012345678901234567890..." This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. *Note:* In Rails versions prior to 3.0.4, this raised an <tt>ActionController::InvalidAuthenticityToken</tt> error. +It is common to use persistent cookies to store user information, with +cookies.permanent+ for example. In this case, the cookies will not be cleared and the out of the box CSRF protection will not be effective. If you are using a different cookie store than the session for this information, you must handle what to do with it yourself: + +<ruby> +def handle_unverified_request + super + sign_out_user # Example method that will destroy the user cookies. +end +</ruby> + +The above method can be placed in the +ApplicationController+ and will be called when a CSRF token is not present on a non-GET request. + Note that _(highlight)cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later. h3. Redirection and Files @@ -244,7 +255,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f h4. Redirection --- _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._ +WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._ Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action: @@ -272,7 +283,7 @@ This example is a Base64 encoded JavaScript which displays a simple message box. h4. File Uploads --- _Make sure file uploads don't overwrite important files, and process media files asynchronously._ +NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._ Many web applications allow users to upload files. _(highlight)File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user. @@ -297,7 +308,7 @@ The solution to this is best to _(highlight)process media files asynchronously_: h4. Executable Code in File Uploads --- _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._ +WARNING: _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._ The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file “file.cgi” with code in it, which will be executed when someone downloads the file. @@ -305,7 +316,7 @@ _(highlight)If your Apache DocumentRoot points to Rails' /public directory, do n h4. File Downloads --- _Make sure users cannot download arbitrary files._ +NOTE: _Make sure users cannot download arbitrary files._ Just as you have to filter file names for uploads, you have to do so for downloads. The send_file() method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded: @@ -327,7 +338,7 @@ Another (additional) approach is to store the file names in the database and nam h3. Intranet and Admin Security --- _Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world._ +Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world. In 2007 there was the first tailor-made trojan which stole information from an Intranet, namely the "Monster for employers" web site of Monster.com, an online recruitment web application. Tailor-made Trojans are very rare, so far, and the risk is quite low, but it is certainly a possibility and an example of how the security of the client host is important, too. However, the highest threat to Intranet and Admin applications are XSS and CSRF.
@@ -359,7 +370,7 @@ The common admin interface works like this: it's located at www.example.com/admi h3. Mass Assignment --- _Without any precautions Model.new(params[:model]) allows attackers to set any database column's value._ +WARNING: _Without any precautions +Model.new(params[:model]+) allows attackers to set any database column's value._ The mass-assignment feature may become a problem, as it allows an attacker to set any model's attributes by manipulating the hash passed to a model's +new()+ method: @@ -471,7 +482,7 @@ This will create an empty whitelist of attributes available for mass-assignment h3. User Management --- _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._ +NOTE: _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._ There are a number of authentication plug-ins for Rails available. Good ones, such as the popular "devise":https://github.com/plataformatec/devise and "authlogic":https://github.com/binarylogic/authlogic, store only encrypted passwords, not plain-text passwords. In Rails 3.1 you can use the built-in +has_secure_password+ method which has similar features. @@ -498,7 +509,7 @@ And thus it found the first user in the database, returned it and logged him in. h4. Brute-Forcing Accounts --- _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._ +NOTE: _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._ A list of user names for your web application may be misused to brute-force the corresponding passwords, because most people don't use sophisticated passwords. Most passwords are a combination of dictionary words and possibly numbers. So armed with a list of user names and a dictionary, an automatic program may find the correct password in a matter of minutes. @@ -510,7 +521,7 @@ In order to mitigate such attacks, _(highlight)display a generic error message o h4. Account Hijacking --- _Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?_ +Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?. h5. Passwords @@ -526,7 +537,7 @@ Depending on your web application, there may be more ways to hijack the user's a h4. CAPTCHAs --- _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._ +INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._ But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is "reCAPTCHA":http://recaptcha.net/ which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. "ReCAPTCHA":http://ambethia.com/recaptcha/ is also a Rails plug-in with the same name as the API. @@ -553,7 +564,7 @@ Note that this protects you only from automatic bots, targeted tailor-made bots h4. Logging --- _Tell Rails not to put passwords in the log files._ +WARNING: _Tell Rails not to put passwords in the log files._ By default, Rails logs all requests being made to the web application. But log files can be a huge security issue, as they may contain login credentials, credit card numbers et cetera. When designing a web application security concept, you should also think about what will happen if an attacker got (full) access to the web server. Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text. You can _(highlight)filter certain request parameters from your log files_ by appending them to <tt>config.filter_parameters</tt> in the application configuration. These parameters will be marked [FILTERED] in the log. @@ -563,7 +574,7 @@ config.filter_parameters << :password h4. Good Passwords --- _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._ +INFO: _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._ Bruce Schneier, a security technologist, "has analyzed":http://www.schneier.com/blog/archives/2006/12/realworld_passw.html 34,000 real-world user names and passwords from the MySpace phishing attack mentioned <a href="#examples-from-the-underground">below</a>. It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are: @@ -575,7 +586,7 @@ A good password is a long alphanumeric combination of mixed cases. As this is qu h4. Regular Expressions --- _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._ +INFO: _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._ Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books make this wrong. So how is this a security threat? Imagine you have a File model and you validate the file name by a regular expression like this: @@ -599,7 +610,7 @@ Whereas %0A is a line feed in URL encoding, so Rails automatically converts it t h4. Privilege Escalation --- _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._ +WARNING: _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._ The most common parameter that a user might tamper with, is the id parameter, as in +http://www.domain.com/project/1+, whereas 1 is the id. It will be available in params in the controller. There, you will most likely do something like this: @@ -619,13 +630,13 @@ Don't be fooled by security by obfuscation and JavaScript security. The Web Deve h3. Injection --- _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._ +INFO: _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._ Injection is very tricky, because the same code or parameter can be malicious in one context, but totally harmless in another. A context can be a scripting, query or programming language, the shell or a Ruby/Rails method. The following sections will cover all important contexts where injection attacks may happen. The first section, however, covers an architectural decision in connection with Injection. h4. Whitelists versus Blacklists --- _When sanitizing, protecting or verifying something, whitelists over blacklists._ +NOTE: _When sanitizing, protecting or verifying something, whitelists over blacklists._ A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_: @@ -640,7 +651,7 @@ Whitelists are also a good approach against the human factor of forgetting somet h4. SQL Injection --- _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._ +INFO: _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._ h5(#sql-injection-introduction). Introduction @@ -719,7 +730,7 @@ The array or hash form is only available in model instances. You can try +saniti h4. Cross-Site Scripting (XSS) --- _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._ +INFO: _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._ h5. Entry Points @@ -847,7 +858,7 @@ The MySpace Samy worm will be discussed in the CSS Injection section. h4. CSS Injection --- _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._ +INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._ CSS Injection is explained best by a well-known worm, the "MySpace Samy worm":http://namb.la/popular/tech.html. This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, but it creates too much traffic on MySpace, so that the site goes offline. The following is a technical explanation of the worm. @@ -887,7 +898,7 @@ This example, again, showed that a blacklist filter is never complete. However, h4. Textile Injection --- _If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS._ +If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS. For example, RedCloth translates +_test_+ to <em>test<em>, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS. Get the "all-new version 4":http://www.redcloth.org that removed serious bugs. However, even that version has "some security bugs":http://www.rorsecurity.info/journal/2008/10/13/new-redcloth-security.html, so the countermeasures still apply. Here is an example for version 3.0.4: @@ -916,13 +927,13 @@ It is recommended to _(highlight)use RedCloth in combination with a whitelist in h4. Ajax Injection --- _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._ +NOTE: _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._ If you use the "in_place_editor plugin":http://dev.rubyonrails.org/browser/plugins/in_place_editing, or actions that return a string, rather than rendering a view, _(highlight)you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method. h4. Command Line Injection --- _Use user-supplied command line parameters with caution._ +NOTE: _Use user-supplied command line parameters with caution._ If your application has to execute commands in the underlying operating system, there are several methods in Ruby: exec(command), syscall(command), system(command) and `command`. You will have to be especially careful with these functions if the user may enter the whole command, or a part of it. This is because in most shells, you can execute another command at the end of the first one, concatenating them with a semicolon (;) or a vertical bar (|). @@ -936,7 +947,7 @@ system("/bin/echo","hello; rm *") h4. Header Injection --- _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._ +WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._ HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _(highlight)Remember to escape these header fields, too._ For example when you display the user agent in an administration area. diff --git a/guides/source/upgrading_ruby_on_rails.textile b/guides/source/upgrading_ruby_on_rails.textile index 02407a5fe8..6cdc6ab289 100644 --- a/guides/source/upgrading_ruby_on_rails.textile +++ b/guides/source/upgrading_ruby_on_rails.textile @@ -34,17 +34,25 @@ h4(#plugins4_0). vendor/plugins Rails 4.0 no longer supports loading plugins from <tt>vendor/plugins</tt>. You must replace any plugins by extracting them to gems and adding them to your Gemfile. If you choose not to make them gems, you can move them into, say, <tt>lib/my_plugin/*</tt> and add an appropriate initializer in <tt>config/initializers/my_plugin.rb</tt>. -h4(#identity_map4_0). IdentityMap +h4(#identity_map4_0). Identity Map -Rails 4.0 has removed <tt>IdentityMap</tt> from <tt>ActiveRecord</tt>, due to "some inconsistencies with associations":https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: <tt>config.active_record.identity_map</tt>. +Rails 4.0 has removed the identity map from Active Record, due to "some inconsistencies with associations":https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: <tt>config.active_record.identity_map</tt>. -h4(#active_model4_0). ActiveModel +h4(#active_record4_0). Active Record -Rails 4.0 has changed how errors attach with the ConfirmationValidator. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>. +The <tt>delete</tt> method in collection associations can now receive <tt>Fixnum</tt> or <tt>String</tt> arguments as record ids, besides records, pretty much like the <tt>destroy</tt> method does. Previously it raised <tt>ActiveRecord::AssociationTypeMismatch</tt> for such arguments. From Rails 4.0 on <tt>delete</tt> automatically tries to find the records matching the given ids before deleting them. -h4(#action_pack4_0). ActionPack +h4(#active_model4_0). Active Model -Rails 4.0 changed how <tt>assert_generates</tt>, <tt>assert_recognizes</tt>, and <tt>assert_routing</tt> work. Now all these assertions raise <tt>Assertion</tt> instead of <tt>RoutingError</tt>. +Rails 4.0 has changed how errors attach with the <tt>ActiveModel::Validations::ConfirmationValidator</tt>. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>. + +h4(#action_pack4_0). Action Pack + +Rails 4.0 changed how <tt>assert_generates</tt>, <tt>assert_recognizes</tt>, and <tt>assert_routing</tt> work. Now all these assertions raise <tt>Assertion</tt> instead of <tt>ActionController::RoutingError</tt>. + +h4(#helpers_order). Helpers Loading Order + +The loading order of helpers from more than one directory has changed in Rails 4.0. Previously, helpers from all directories were gathered and then sorted alphabetically. After upgrade to Rails 4.0 helpers will preserve the order of loaded directories and will be sorted alphabetically only within each directory. Unless you explicitly use <tt>helpers_path</tt> parameter, this change will only impact the way of loading helpers from engines. If you rely on the fact that particular helper from engine loads before or after another helper from application or another engine, you should check if correct methods are available after upgrade. If you would like to change order in which engines are loaded, you can use <tt>config.railties_order=</tt> method. h3. Upgrading from Rails 3.1 to Rails 3.2 |