These release notes cover the major changes, but do not include each bug-fix and changes. If you want to see everything, check out the "list of commits":https://github.com/rails/rails/commits/master in the main Rails repository on GitHub.
endprologue.
h3. Upgrading to Rails 4.0
TODO. This is a WIP guide.
If you're upgrading an existing application, it's a great idea to have good test coverage before going in. You should also first upgrade to Rails 3.2 in case you haven't and make sure your application still runs as expected before attempting an update to Rails 4.0. Then take heed of the following changes:
Rails 4.0 requires Ruby 1.9.3 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible.
* Rails 4.0 removes <tt>vendor/plugins</tt> completely. You have to replace these plugins by extracting them as gems and adding them in your Gemfile. If you choose not to make them gems, you can move them into, say, <tt>lib/my_plugin/*</tt> and add an appropriate initializer in <tt>config/initializers/my_plugin.rb</tt>.
TODO: Configuration changes in environment files
h3. Creating a Rails 4.0 application
<shell>
# You should have the 'rails' rubygem installed
$ rails new myapp
$ cd myapp
</shell>
h4. Vendoring Gems
Rails now uses a +Gemfile+ in the application root to determine the gems you require for your application to start. This +Gemfile+ is processed by the "Bundler":https://github.com/carlhuda/bundler gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems.
More information: "Bundler homepage":http://gembundler.com
h4. Living on the Edge
+Bundler+ and +Gemfile+ makes freezing your Rails application easy as pie with the new dedicated +bundle+ command. If you want to bundle straight from the Git repository, you can pass the +--edge+ flag:
<shell>
$ rails new myapp --edge
</shell>
If you have a local checkout of the Rails repository and want to generate an application using that, you can pass the +--dev+ flag:
<shell>
$ ruby /path/to/rails/railties/bin/rails new myapp --dev
* The application generator generates <tt>public/humans.txt</tt> with some basic data.
* Add <tt>config.queue_consumer</tt> to allow the default consumer to be configurable.
* Add <tt>Rails.queue</tt> as an interface with a default implementation that consumes jobs in a separate thread.
* Remove <tt>Rack::SSL</tt> in favour of <tt>ActionDispatch::SSL</tt>.
* Allow to set class that will be used to run as a console, other than IRB, with <tt>Rails.application.config.console=</tt>. It's best to add it to console block.
* Add a convenience method <tt>hide!</tt> to Rails generators to hide the current generator namespace from showing when running <tt>rails generate</tt>.
* Extracted redirect logic from <tt>ActionController::ForceSSL::ClassMethods.force_ssl</tt> into <tt>ActionController::ForceSSL#force_ssl_redirect</tt>.
* URL path parameters with invalid encoding now raise <tt>ActionController::BadRequest</tt>.
* Malformed query and request parameter hashes now raise <tt>ActionController::BadRequest</tt>.
* +respond_to+ and +respond_with+ now raise <tt>ActionController::UnknownFormat</tt> instead of directly returning head 406. The exception is rescued and converted to 406 in the exception handling middleware.
* Session arguments passed to process calls in functional tests are now merged into the existing session, whereas previously they would replace the existing session. This change may break some existing tests if they are asserting the exact contents of the session but should not break existing tests that only assert individual keys.
* Copy literal route constraints to defaults so that url generation know about them. The copied constraints are <tt>:protocol</tt>, <tt>:subdomain</tt>, <tt>:domain</tt>, <tt>:host</tt> and <tt>:port</tt>.
* Adds support for the PATCH verb: Request objects respond to <tt>patch?</tt>. Routes now have a new +patch+ method, and understand +:patch+ in the existing places where a verb is configured, like <tt>:via</tt>. Functional tests have a new method +patch+ and integration tests have a new method +patch_via_redirect+.
If <tt>:patch</tt> is the default verb for updates, edits are tunneled as <tt>PATCH</tt> rather than as <tt>PUT</tt> and routing acts accordingly.
* Templates without a handler extension now raises a deprecation warning but still defaults to +ERb+. In future releases, it will simply return the template content.
* Add a +divider+ option to +grouped_options_for_select+ to generate a separator optgroup automatically, and deprecate prompt as third argument, in favor of using an options hash.
* Add +time_field+ and +time_field_tag+ helpers which render an <tt>input[type="time"]</tt> tag.
* Removed old +text_helper+ apis for +highlight+, +excerpt+ and +word_wrap+.
* Remove the leading \n added by textarea on +assert_select+.
* Changed default value for <tt>config.action_view.embed_authenticity_token_in_remote_forms</tt> to false. This change breaks remote forms that need to work also without JavaScript, so if you need such behavior, you can either set it to true or explicitly pass <tt>:authenticity_token => true</tt> in form options.
* Make possible to use a block in +button_to+ helper if button text is hard to fit into the name parameter:
* Replace +include_seconds+ boolean argument with <tt>:include_seconds => true</tt> option in +distance_of_time_in_words+ and +time_ago_in_words+ signature.
* Remove +button_to_function+ and +link_to_function+ helpers.
* Add +color_field+ and +color_field_tag+ helpers.
* Add +include_hidden+ option to select tag. With <tt>:include_hidden => false</tt> select with multiple attribute doesn't generate hidden input with blank value.
* Removed default size option from the +text_field+, +search_field+, +telephone_field+, +url_field+, +email_field+ helpers.
* Removed default cols and rows options from the +text_area+ helper.
* Adds +image_url+, +javascript_url+, +stylesheet_url+, +audio_url+, +video_url+, and +font_url+ to assets tag helper. These URL helpers will return the full path to your assets. This is useful when you are going to reference this asset from external host.
* Allow +value_method+ and +text_method+ arguments from +collection_select+ and +options_from_collection_for_select+ to receive an object that responds to <tt>:call</tt> such as a proc, to evaluate the option in the current element context. This works the same way with +collection_radio_buttons+ and +collection_check_boxes+.
* +check_box+ helper with <tt>:disabled => true</tt> will generate a +disabled+ hidden field to conform with the HTML convention where disabled fields are not submitted with the form. This is a behavior change, previously the hidden tag had a value of the disabled checkbox.
* Add <tt>add_reference</tt> and <tt>remove_reference</tt> schema statements. Aliases, <tt>add_belongs_to</tt> and <tt>remove_belongs_to</tt> are acceptable. References are reversible.
<ruby>
# Create a user_id column
add_reference(:products, :user)
# Create a supplier_id, supplier_type columns and appropriate index
* <tt>FinderMethods#exists?</tt> now returns <tt>false</tt> with the <tt>false</tt> argument.
* Added support for specifying the precision of a timestamp in the postgresql adapter. So, instead of having to incorrectly specify the precision using the <tt>:limit</tt> option, you may use <tt>:precision</tt>, as intended. For example, in a migration:
<ruby>
def change
create_table :foobars do |t|
t.timestamps :precision => 0
end
end
</ruby>
* Allow <tt>ActiveRecord::Relation#pluck</tt> to accept multiple columns. Returns an array of arrays containing the typecasted values:
<ruby>
Person.pluck(:id, :name)
# SELECT people.id, people.name FROM people
# => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
</ruby>
* Improve the derivation of HABTM join table name to take account of nesting. It now takes the table names of the two models, sorts them lexically and then joins them, stripping any common prefix from the second table name. Some examples:
<plain>
Top level models (Category <=> Product)
Old: categories_products
New: categories_products
Top level models with a global table_name_prefix (Category <=> Product)
Old: site_categories_products
New: site_categories_products
Nested models in a module without a table_name_prefix method (Admin::Category <=> Admin::Product)
Old: categories_products
New: categories_products
Nested models in a module with a table_name_prefix method (Admin::Category <=> Admin::Product)
Old: categories_products
New: admin_categories_products
Nested models in a parent model (Catalog::Category <=> Catalog::Product)
Old: categories_products
New: catalog_categories_products
Nested models in different parent models (Catalog::Category <=> Content::Page)
Old: categories_pages
New: catalog_categories_content_pages
</plain>
* Move HABTM validity checks to <tt>ActiveRecord::Reflection</tt>. One side effect of this is to move when the exceptions are raised from the point of declaration to when the association is built. This is consistant with other association validity checks.
* Added <tt>stored_attributes</tt> hash which contains the attributes stored using <tt>ActiveRecord::Store</tt>. This allows you to retrieve the list of attributes you've defined.
* <tt>composed_of</tt> was removed. You'll have to write your own accessor and mutator methods if you'd like to use value objects to represent some portion of your models. So, instead of:
* PostgreSQL default log level is now 'warning', to bypass the noisy notice messages. You can change the log level using the <tt>min_messages</tt> option available in your <tt>config/database.yml</tt>.
* Add uuid datatype support to PostgreSQL adapter.
* <tt>update_attribute</tt> has been removed. Use <tt>update_column</tt> if you want to bypass mass-assignment protection, validations, callbacks, and touching of updated_at. Otherwise please use <tt>update_attributes</tt>.
* Added <tt>ActiveRecord::Migration.check_pending!</tt> that raises an error if migrations are pending.
* Added <tt>#destroy!</tt> which acts like <tt>#destroy</tt> but will raise an <tt>ActiveRecord::RecordNotDestroyed</tt> exception instead of returning <tt>false</tt>.
* Allow blocks for count with <tt>ActiveRecord::Relation</tt>, to work similar as <tt>Array#count</tt>: <tt>Person.where("age > 26").count { |person| person.gender == 'female' }</tt>
* Added support to <tt>CollectionAssociation#delete</tt> for passing fixnum or string values as record ids. This finds the records responding to the ids and deletes them.
* +mysql+ and +mysql2+ connections will set <tt>SQL_MODE=STRICT_ALL_TABLES</tt> by default to avoid silent data loss. This can be disabled by specifying <tt>strict: false</tt> in <tt>config/database.yml</tt>.
* Added default order to <tt>ActiveRecord::Base#first</tt> to assure consistent results among diferent database engines. Introduced <tt>ActiveRecord::Base#take</tt> as a replacement to the old behavior.
* Added an <tt>:index</tt> option to automatically create indexes for +references+ and +belongs_to+ statements in migrations. This can be either a boolean or a hash that is identical to options available to the +add_index+ method:
Generators have also been updated to use the new syntax.
* Added bang methods for mutating <tt>ActiveRecord::Relation</tt> objects. For example, while <tt>foo.where(:bar)</tt> will return a new object leaving foo unchanged, <tt>foo.where!(:bar)</tt> will mutate the foo object.
* Added <tt>#find_by</tt> and <tt>#find_by!</tt> to mirror the functionality provided by dynamic finders in a way that allows dynamic input more easily:
* Remove IdentityMap - IdentityMap has never graduated to be an "enabled-by-default" feature, due to some inconsistencies with associations, as described in this "commit":https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. Hence the removal from the codebase, until such issues are fixed.
* Implemented <tt>ActiveRecord::Relation#none</tt> method which returns a chainable relation with zero records (an instance of the +NullRelation+ class). Any subsequent condition chained to the returned relation will continue generating an empty relation and will not fire any query to the database.
This behaviour relies on matching SQL string, which is an inherently flawed idea unless we write an SQL parser, which we do not wish to do. Therefore, it is now deprecated.
To avoid deprecation warnings and for future compatibility, you must explicitly state which tables you reference, when using SQL snippets:
Note that you do not need to explicitly specify references in the following cases, as they can be automatically inferred:
<ruby>
Post.where(comments: { name: 'foo' })
Post.where('comments.name' => 'foo')
Post.order('comments.name')
</ruby>
You also do not need to worry about this unless you are doing eager loading. Basically, don't worry unless you see a deprecation warning or (in future releases) an SQL error due to a missing JOIN.
* Support for the +schema_info+ table has been dropped. Please switch to +schema_migrations+.
* Connections *must* be closed at the end of a thread. If not, your connection pool can fill and an exception will be raised.
* Added the <tt>ActiveRecord::Model</tt> module which can be included in a class as an alternative to inheriting from <tt>ActiveRecord::Base</tt>:
<ruby>
class Post
include ActiveRecord::Model
end
</ruby>
* PostgreSQL hstore records can be created.
* PostgreSQL hstore types are automatically deserialized from the database.
h4(#activerecord_deprecations). Deprecations
* Deprecated most of the 'dynamic finder' methods. All dynamic methods except for +find_by_...+ and +find_by_...!+ are deprecated. Here's how you can rewrite the code:
<ruby>
find_all_by_... can be rewritten using where(...)
find_last_by_... can be rewritten using where(...).last
scoped_by_... can be rewritten using where(...)
find_or_initialize_by_... can be rewritten using where(...).first_or_initialize
find_or_create_by_... can be rewritten using where(...).first_or_create
find_or_create_by_...! can be rewritten using where(...).first_or_create!
</ruby>
The implementation of the deprecated dynamic finders has been moved to the +active_record_deprecated_finders+ gem.
* Deprecated the old-style hash based finder API. This means that methods which previously accepted "finder options" no longer do. For example this:
This could save you a lot of work if there is a lot of old-style finder usage in your application.
Calling <tt>Post.scoped(options)</tt> is a shortcut for <tt>Post.scoped.merge(options)</tt>. <tt>Relation#merge</tt> now accepts a hash of options, but they must be identical to the names of the equivalent finder method. These are mostly identical to the old-style finder option names, except in the following cases:
<plain>
:conditions becomes :where
:include becomes :includes
:extend becomes :extending
</plain>
The code to implement the deprecated features has been moved out to the +active_record_deprecated_finders+ gem. This gem is a dependency of Active Record in Rails 4.0. It will no longer be a dependency from Rails 4.1, but if your app relies on the deprecated features then you can add it to your own Gemfile. It will be maintained by the Rails core team until Rails 5.0 is released.
Eager scopes are also very complex to implement within Active Record, and there are still bugs. For example, the following does not do what you expect:
* Added deprecation for the :dependent => :restrict association option.
* Up until now has_many and has_one, :dependent => :restrict option raised a DeleteRestrictionError at the time of destroying the object. Instead, it will add an error on the model.
* To fix this warning, make sure your code isn't relying on a DeleteRestrictionError and then add config.active_record.dependent_restrict_raises = false to your application config.
* New rails application would be generated with the config.active_record.dependent_restrict_raises = false in the application config.
* Changed <tt>AM::Serializers::JSON.include_root_in_json</tt> default value to false. Now, AM Serializers and AR objects have the same default behaviour.
* <tt>ActionView::Helpers::NumberHelper</tt> methods have been moved to <tt>ActiveSupport::NumberHelper</tt> and are now available via <tt>Numeric#to_s</tt>.
* <tt>Numeric#to_s</tt> now accepts the formatting options :phone, :currency, :percentage, :delimited, :rounded, :human, and :human_size.
* Add <tt>Hash#transform_keys</tt>, <tt>Hash#transform_keys!</tt>, <tt>Hash#deep_transform_keys</tt> and <tt>Hash#deep_transform_keys!</tt>.
* Changed xml type datetime to dateTime (with upper case letter T).
* Add <tt>:instance_accessor</tt> option for <tt>class_attribute</tt>.
* +constantize+ now looks in the ancestor chain.
* Add <tt>Hash#deep_stringify_keys</tt> and <tt>Hash#deep_stringify_keys!</tt> to convert all keys from a +Hash+ instance into strings.
* Add <tt>Hash#deep_symbolize_keys</tt> and <tt>Hash#deep_symbolize_keys!</tt> to convert all keys from a +Hash+ instance into symbols.
* <tt>BufferedLogger</tt> is deprecated. Use <tt>ActiveSupport::Logger</tt> or the +logger+ from Ruby stdlib.
* Deprecates the compatibility method <tt>Module#local_constant_names</tt> and use <tt>Module#local_constants</tt> instead (which returns symbols).
h3. Credits
See the "full list of contributors to Rails":http://contributors.rubyonrails.org/ for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them.