diff options
32 files changed, 260 insertions, 102 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 8f74ac0928..487e57be7b 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -21,7 +21,7 @@ *Olek Janiszewski* * Eager loading made to use relation's `in_clause_length` instead of host's one. - Fix #8474 + Fixes #8474. *Boris Staal* @@ -29,7 +29,7 @@ *Nate Berkopec* * Do not render views when mail() isn't called. - Fix #7761 + Fixes #7761. *Yves Senn* diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 1050626884..157a038b7c 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,20 @@ ## Rails 4.0.0 (unreleased) ## +* Fix incorrectly appended square brackets to a multiple select box + if an explicit name has been given and it already ends with "[]" + + Before: + + select(:category, [], {}, multiple: true, name: "post[category][]") + # => <select name="post[category][][]" ...> + + After: + + select(:category, [], {}, multiple: true, name: "post[category][]") + # => <select name="post[category][]" ...> + + *Olek Janiszewski* + * Fixed regression when using `assert_template` to verify files sent using `render file: 'README.md'`. Fixes #9464. @@ -237,12 +252,12 @@ Client-IP and Remote-Addr headers, in that order. Document the rationale for that decision, and describe the options that can be passed to the RemoteIp middleware to change it. - Fix #7979 + Fixes #7979. *André Arko*, *Steve Klabnik*, *Alexey Gaziev* * Do not append second slash to `root_url` when using `trailing_slash: true` - Fix #8700 + Fixes #8700. Before: @@ -270,7 +285,7 @@ * Do not append `charset=` parameter when `head` is called with a `:content_type` option. - Fix #8661. + Fixes #8661. *Yves Senn* @@ -428,7 +443,7 @@ * Render every partial with a new `ActionView::PartialRenderer`. This resolves issues when rendering nested partials. - Fix #8197. + Fixes #8197. *Yves Senn* @@ -436,7 +451,7 @@ of mime types where template text is not html escaped by default. It prevents `Jack & Joe` from rendering as `Jack & Joe` for the whitelisted mime types. The default whitelist contains `text/plain`. - Fix #7976. + Fixes #7976. *Joost Baaij* @@ -452,7 +467,7 @@ check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1) # => <input name=\"post[foo][comment_ids][]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids][]\" type=\"checkbox\" value=\"1\" /> - Fix #8108. + Fixes #8108. *Daniel Fox, Grant Hutchins & Trace Wax* @@ -475,7 +490,7 @@ *Josh Peek* * `assert_template` can be used to assert on the same template with different locals - Fix #3675. + Fixes #3675. *Yves Senn* @@ -486,7 +501,7 @@ * Accept `:remote` as symbolic option for `link_to` helper. *Riley Lynch* * Warn when the `:locals` option is passed to `assert_template` outside of a view test case - Fix #3415. + Fixes #3415. *Yves Senn* @@ -510,12 +525,12 @@ * Rename internal variables on `ActionController::TemplateAssertions` to prevent naming collisions. `@partials`, `@templates` and `@layouts` are now prefixed with an underscore. - Fix #7459. + Fixes #7459. *Yves Senn* * `resource` and `resources` don't modify the passed options hash. - Fix #7777. + Fixes #7777. *Yves Senn* @@ -579,7 +594,7 @@ *Guillermo Iguaran* * Log now displays the correct status code when an exception is raised. - Fix #7646. + Fixes #7646. *Yves Senn* diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index 3d274e7dd7..7318c8b7ec 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -48,6 +48,11 @@ module ActionController info("Sent data #{event.payload[:filename]} (#{event.duration.round(1)}ms)") end + def unpermitted_parameters(event) + unpermitted_keys = event.payload[:keys] + debug("Unpermitted parameters: #{unpermitted_keys.join(", ")}") + end + %w(write_fragment read_fragment exist_fragment? expire_fragment expire_page write_page).each do |method| class_eval <<-METHOD, __FILE__, __LINE__ + 1 diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index 32e5afa335..9d628c916f 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -14,6 +14,7 @@ module ActionController # response.stream.write "hello world\n" # sleep 1 # } + # ensure # response.stream.close # end # end diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index e4dcd3213f..acad8a0799 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -339,7 +339,8 @@ module ActionController if unpermitted_keys.any? case self.class.action_on_unpermitted_parameters when :log - ActionController::Base.logger.debug "Unpermitted parameters: #{unpermitted_keys.join(", ")}" + name = "unpermitted_parameters.action_controller" + ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys) when :raise raise ActionController::UnpermittedParameters.new(unpermitted_keys) end diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 1bad82159a..5afe435459 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -180,7 +180,7 @@ module ActionView # <title>My Website</title> # <%= yield :script %> # </head> - # <body class="<%= content_for?(:right_col) ? 'one-column' : 'two-column' %>"> + # <body class="<%= content_for?(:right_col) ? 'two-column' : 'one-column' %>"> # <%= yield %> # <%= yield :right_col %> # </body> diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb index 3d597079c4..aef1572290 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionpack/lib/action_view/helpers/tags/base.rb @@ -84,7 +84,7 @@ module ActionView options["id"] = options.fetch("id"){ tag_id } end - options["name"] += "[]" if options["multiple"] + options["name"] += "[]" if options["multiple"] && !options["name"].ends_with?("[]") options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence end diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 04cdd068c8..29d63d9653 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -575,6 +575,14 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_select_with_multiple_and_with_explicit_name_ending_with_brackets + output_buffer = select(:post, :category, [], {include_hidden: false}, multiple: true, name: 'post[category][]') + assert_dom_equal( + "<select multiple=\"multiple\" id=\"post_category\" name=\"post[category][]\"></select>", + output_buffer + ) + end + def test_select_with_multiple_and_disabled_to_add_disabled_hidden_input output_buffer = select(:post, :category, "", {}, :multiple => true, :disabled => true) assert_dom_equal( diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 8c54ec3d45..c6d7b0b5d3 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -5,23 +5,25 @@ Example: - # given User has_secure_password. + # Given User has_secure_password. @user.password = "" @user.password_confirmation = "" @user.valid?(:update) # used to be false + *Yves Senn* + * `validates_confirmation_of` does not override writer methods for the confirmation attribute if no reader is defined. Example: class Blog - def title=(new_title) - @title = new_title.downcase - end + def title=(new_title) + @title = new_title.downcase + end - # previously this would override the setter above. - validates_confirmation_of :title + # previously this would override the setter above. + validates_confirmation_of :title end *Yves Senn* diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 63d5bbb9ee..093e9ff6d2 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,8 +1,17 @@ ## Rails 4.0.0 (unreleased) ## -* Fix ActiveRecord `subclass_from_attrs` when `eager_load` is false. - It cannot find subclass because all classes are loaded automatically - when it needs. +* `connection` is deprecated as an instance method. + This allows end-users to have a `connection` method on their models + without clashing with Active Record internals. + + *Ben Moss* + +* When copying migrations, preserve their magic comments and content encoding. + + *OZAWA Sakuro* + +* Fix `subclass_from_attrs` when `eager_load` is false. It cannot find + subclass because all classes are loaded automatically when it needs. *Dmitry Vorotilin* @@ -116,7 +125,7 @@ *Yves Senn* * Assigning "0.0" to a nullable numeric column does not make it dirty. - Fix #9034. + Fixes #9034. Example: @@ -551,17 +560,17 @@ *Marc-André Lafortune* * Serialized attributes can be serialized in integer columns. - Fix #8575. + Fixes #8575. *Rafael Mendonça França* * Keep index names when using `alter_table` with sqlite3. - Fix #3489. + Fixes #3489. *Yves Senn* * Add ability for postgresql adapter to disable user triggers in `disable_referential_integrity`. - Fix #5523. + Fixes #5523. *Gary S. Weaver* @@ -584,7 +593,7 @@ *Matthew Robertson* * Recognize migrations placed in directories containing numbers and 'rb'. - Fix #8492 + Fixes #8492. *Yves Senn* @@ -642,13 +651,13 @@ * Fix performance problem with `primary_key` method in PostgreSQL adapter when having many schemas. Uses `pg_constraint` table instead of `pg_depend` table which has many records in general. - Fix #8414 + Fixes #8414. *kennyj* * Do not instantiate intermediate Active Record objects when eager loading. These records caused `after_find` to run more than expected. - Fix #3313 + Fixes #3313. *Yves Senn* @@ -669,12 +678,13 @@ * Fix dirty attribute checks for `TimeZoneConversion` with nil and blank datetime attributes. Setting a nil datetime to a blank string should not - result in a change being flagged. Fix #8310 + result in a change being flagged. + Fixes #8310. *Alisdair McDiarmid* * Prevent mass assignment to the type column of polymorphic associations when using `build` - Fix #8265 + Fixes #8265. *Yves Senn* @@ -727,7 +737,7 @@ *Bogdan Gusiev* * `:counter_cache` option for `has_many` associations to support custom named counter caches. - Fix #7993 + Fixes #7993. *Yves Senn* @@ -751,7 +761,7 @@ *Nikita Afanasenko* * Use query cache/uncache when using `DATABASE_URL`. - Fix #6951. + Fixes #6951. *kennyj* @@ -760,7 +770,7 @@ *Henrik Nyh* * The `create_table` method raises an `ArgumentError` when the primary key column is redefined. - Fix #6378 + Fixes #6378. *Yves Senn* @@ -870,7 +880,7 @@ *Alexey Muranov* * The postgres adapter now supports tables with capital letters. - Fix #5920 + Fixes #5920. *Yves Senn* @@ -892,7 +902,7 @@ *Francesco Rodriguez* * Fix `reset_counters` crashing on `has_many :through` associations. - Fix #7822. + Fixes #7822. *lulalala* @@ -967,7 +977,7 @@ *Guillermo Iguaran* * Fix the return of querying with an empty hash. - Fix #6971. + Fixes #6971. User.where(token: {}) @@ -983,7 +993,7 @@ * Fix creation of through association models when using `collection=[]` on a `has_many :through` association from an unsaved model. - Fix #7661. + Fixes #7661. *Ernie Miller* diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 35e4eb19a4..519e9112b8 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1024,7 +1024,7 @@ module ActiveRecord # [collection<<(object, ...)] # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. # Note that this operation instantly fires update sql without waiting for the save or update call on the - # parent object. + # parent object, unless the parent object is a new record. # [collection.delete(object, ...)] # Removes one or more objects from the collection by setting their foreign keys to +NULL+. # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>, @@ -1231,7 +1231,7 @@ module ActiveRecord # its owner is destroyed: # # * <tt>:destroy</tt> causes the associated object to also be destroyed - # * <tt>:delete</tt> causes the asssociated object to be deleted directly from the database (so callbacks will not execute) + # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute) # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed. # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object @@ -1433,7 +1433,7 @@ module ActiveRecord # Adds one or more objects to the collection by creating associations in the join table # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method). # Note that this operation instantly fires update sql without waiting for the save or update call on the - # parent object. + # parent object, unless the parent object is a new record. # [collection.delete(object, ...)] # Removes one or more objects from the collection by removing their associations from the join table. # This does not destroy the objects. diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index 93618721bb..bb3e3db379 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -26,7 +26,7 @@ module ActiveRecord join_table[reflection.association_foreign_key] => record.id ) - owner.connection.insert stmt + owner.class.connection.insert stmt end record @@ -41,7 +41,7 @@ module ActiveRecord def delete_records(records, method) if sql = options[:delete_sql] records = load_target if records == :all - records.each { |record| owner.connection.delete(interpolate(sql, record)) } + records.each { |record| owner.class.connection.delete(interpolate(sql, record)) } else relation = join_table condition = relation[reflection.foreign_key].eq(owner.id) @@ -53,7 +53,7 @@ module ActiveRecord ) end - owner.connection.delete(relation.where(condition).compile_delete) + owner.class.connection.delete(relation.where(condition).compile_delete) end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 899fe7d7c7..72371be657 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -324,6 +324,7 @@ module ActiveRecord # also be used to "borrow" the connection to do database work that isn't # easily done without going straight to SQL. def connection + ActiveSupport::Deprecation.warn("#connection is deprecated in favour of accessing it via the class") self.class.connection end diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 701949e57b..209de78898 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -86,7 +86,7 @@ module ActiveRecord ) ).arel.compile_update(arel_attributes_with_values_for_update(attribute_names)) - affected_rows = connection.update stmt + affected_rows = self.class.connection.update stmt unless affected_rows == 1 raise ActiveRecord::StaleObjectError.new(self, "update") @@ -117,7 +117,7 @@ module ActiveRecord if locking_enabled? column_name = self.class.locking_column column = self.class.columns_hash[column_name] - substitute = connection.substitute_at(column, relation.bind_values.length) + substitute = self.class.connection.substitute_at(column, relation.bind_values.length) relation = relation.where(self.class.arel_table[column_name].eq(substitute)) relation.bind_values << [column, self[column_name].to_i] diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 3d71b784e7..5d7762ec3a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -634,8 +634,17 @@ module ActiveRecord source_migrations = ActiveRecord::Migrator.migrations(path) source_migrations.each do |migration| - source = File.read(migration.filename) - source = "# This migration comes from #{scope} (originally #{migration.version})\n#{source}" + source = File.binread(migration.filename) + inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n" + if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source + # If we have a magic comment in the original migration, + # insert our comment after the first newline(end of the magic comment line) + # so the magic keep working. + # Note that magic comments must be at the first line(except sh-bang). + source[/\n/] = "\n#{inserted_comment}" + else + source = "#{inserted_comment}#{source}" + end if duplicate = destination_migrations.detect { |m| m.name == migration.name } if options[:on_skip] && duplicate.scope != scope.to_s @@ -649,7 +658,7 @@ module ActiveRecord old_path, migration.filename = migration.filename, new_path last = migration - File.open(migration.filename, "w") { |f| f.write source } + File.binwrite(migration.filename, source) copied << migration options[:on_copy].call(scope, migration, old_path) if options[:on_copy] destination_migrations << migration diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 347f023793..b25d0601cb 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -410,7 +410,7 @@ module ActiveRecord def relation_for_destroy pk = self.class.primary_key column = self.class.columns_hash[pk] - substitute = connection.substitute_at(column, 0) + substitute = self.class.connection.substitute_at(column, 0) relation = self.class.unscoped.where( self.class.arel_table[pk].eq(substitute)) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index b0b29f5f42..8ad40ec3f4 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -477,9 +477,8 @@ class CustomConnectionFixturesTest < ActiveRecord::TestCase fixtures :courses self.use_transactional_fixtures = false - def test_connection - assert_kind_of Course, courses(:ruby) - assert_equal Course.connection, courses(:ruby).connection + def test_connection_instance_method_deprecation + assert_deprecated { courses(:ruby).connection } end def test_leaky_destroy diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 6f90500189..f8afb7c591 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -738,6 +738,26 @@ class CopyMigrationsTest < ActiveRecord::TestCase clear end + def test_copying_migrations_preserving_magic_comments + ActiveRecord::Base.timestamped_migrations = false + @migrations_path = MIGRATIONS_ROOT + "/valid" + @existing_migrations = Dir[@migrations_path + "/*.rb"] + + copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/magic"}) + assert File.exists?(@migrations_path + "/4_currencies_have_symbols.bukkits.rb") + assert_equal [@migrations_path + "/4_currencies_have_symbols.bukkits.rb"], copied.map(&:filename) + + expected = "# coding: ISO-8859-15\n# This migration comes from bukkits (originally 1)" + assert_equal expected, IO.readlines(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")[0..1].join.chomp + + files_count = Dir[@migrations_path + "/*.rb"].length + copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/magic"}) + assert_equal files_count, Dir[@migrations_path + "/*.rb"].length + assert copied.empty? + ensure + clear + end + def test_skipping_migrations @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps" @existing_migrations = Dir[@migrations_path + "/*.rb"] diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index eb4ffd4498..766a5c0c90 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -182,9 +182,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_rollback_when_commit_fails - @first.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction) + @first.class.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction) begin - @first.connection.class.class_eval do + @first.class.connection.class.class_eval do def commit_db_transaction; raise "boom!"; end end @@ -194,8 +194,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase assert !@first.save rescue nil assert_equal [:after_rollback], @first.history ensure - @first.connection.class.send(:remove_method, :commit_db_transaction) - @first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) + @first.class.connection.class.send(:remove_method, :commit_db_transaction) + @first.class.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) end end diff --git a/activerecord/test/migrations/magic/1_currencies_have_symbols.rb b/activerecord/test/migrations/magic/1_currencies_have_symbols.rb new file mode 100644 index 0000000000..c066c068c2 --- /dev/null +++ b/activerecord/test/migrations/magic/1_currencies_have_symbols.rb @@ -0,0 +1,12 @@ +# coding: ISO-8859-15 + +class CurrenciesHaveSymbols < ActiveRecord::Migration + def self.up + # We use for default currency symbol + add_column "currencies", "symbol", :string, :default => "" + end + + def self.down + remove_column "currencies", "symbol" + end +end diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 463da488f2..37afb25181 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -178,12 +178,6 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ If migrating down, the given migration / block is run normally. See the [Guide on Migration](https://github.com/rails/rails/blob/master/guides/source/migrations.md#reverting-previous-migrations) -* Adds some metadata columns to `schema_migrations` table. - - * `migrated_at` - * `fingerprint` - an md5 hash of the migration. - * `name` - the filename minus version and extension. - * Adds PostgreSQL array type support. Any datatype can be used to create an array column, with full migration and schema dumper support. * Add `Relation#load` to explicitly load the record and return `self`. diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 5861fc3d54..7e0a8a43d4 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -290,6 +290,20 @@ parameters: params.require(:author).permit(:name, books_attributes: [:title, :id, :_destroy]) ``` +Hashes with integer keys are treated differently and you can declare +the attributes as if they were direct children. You get this kind of +parameters when you use `accepts_nested_attributes_for` in combination +with a `has_many` association: + +```ruby +# To whitelist the following data: +# {"book" => {"title" => "Some Book", +# "chapters_attributes" => { "1" => {"title" => "First Chapter"}, +# "2" => {"title" => "Second Chapter"}}}} + +params.require(:book).permit(:title, chapters_attributes: [:title]) +``` + #### Outside the Scope of Strong Parameters The strong parameter API was designed with the most common use cases diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 8720aae169..31182e9aed 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -403,7 +403,7 @@ If you wish to override the default delivery options (e.g. SMTP credentials) whi ```ruby class UserMailer < ActionMailer::Base - def welcome_email(user,company) + def welcome_email(user, company) @user = user @url = user_url(@user) delivery_options = { user_name: company.smtp_user, password: company.smtp_password, address: company.smtp_host } @@ -412,6 +412,19 @@ class UserMailer < ActionMailer::Base end ``` +### Sending Emails without Template Rendering + +There may be cases in which you want to skip the template rendering step and supply the email body as a string. You can achieve this using the `:body` option. +In such cases don't forget to add the `:content_type` option. Rails will default to `text/plain` otherwise. + +```ruby +class UserMailer < ActionMailer::Base + def welcome_email(user, email_body) + mail(to: user.email, body: email_body, content_type: "text/html", subject: "Already rendered!") + end +end +``` + Receiving Emails ---------------- diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 0d0813c56a..4a4f814917 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1196,6 +1196,61 @@ Using a class method is the preferred way to accept arguments for scopes. These category.posts.created_before(time) ``` +### Merging of scopes + +Just like `where` clauses scopes are merged using `AND` conditions. + +```ruby +class User < ActiveRecord::Base + scope :active, -> { where state: 'active' } + scope :inactive, -> { where state: 'inactive' } +end + +```ruby +User.active.inactive +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'inactive' +``` + +We can mix and match `scope` and `where` conditions and the final sql +will have all conditions joined with `AND` . + +```ruby +User.active.where(state: 'finished') +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'finished' +``` + +If we do want the `last where clause` to win then `Relation#merge` can +be used . + +```ruby +User.active.merge(User.inactive) +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +``` + +One important caveat is that `default_scope` will be overridden by +`scope` and `where` conditions. + +```ruby +class User < ActiveRecord::Base + default_scope { where state: 'pending' } + scope :active, -> { where state: 'active' } + scope :inactive, -> { where state: 'inactive' } +end + +User.all +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' + +User.active +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' + +User.where(state: 'inactive') +# => SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +``` + +As you can see above the `default_scope` is being overridden by both +`scope` and `where` conditions. + + ### Applying a default scope If we wish for a scope to be applied across all queries to the model we can use the @@ -1399,7 +1454,7 @@ Client.select(:id).map { |c| c.id } # or Client.select(:id).map(&:id) # or -Client.select(:id).map { |c| [c.id, c.name] } +Client.select(:id, :name).map { |c| [c.id, c.name] } ``` with diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 6b3be69942..d08000eb69 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -450,7 +450,7 @@ ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*a data # { extra: :information } ``` -You may also subscribe to events matching a regular expresssion. This enables you to subscribe to +You may also subscribe to events matching a regular expression. This enables you to subscribe to multiple events at once. Here's you could subscribe to everything from `ActionController`. ```ruby diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index cb0a7c8026..65c8154064 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -1109,7 +1109,7 @@ end Controls what happens to the associated object when its owner is destroyed: * `:destroy` causes the associated object to also be destroyed -* `:delete` causes the asssociated object to be deleted directly from the database (so callbacks will not execute) +* `:delete` causes the associated object to be deleted directly from the database (so callbacks will not execute) * `:nullify` causes the foreign key to be set to `NULL`. Callbacks are not executed. * `: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 @@ -1463,7 +1463,7 @@ end Controls what happens to the associated objects when their owner is destroyed: * `:destroy` causes all the associated objects to also be destroyed -* `:delete_all` causes all the asssociated objects to be deleted directly from the database (so callbacks will not execute) +* `:delete_all` causes all the associated objects to be deleted directly from the database (so callbacks will not execute) * `:nullify` causes the foreign keys to be set to `NULL`. Callbacks are not executed. * `:restrict_with_exception` causes an exception to be raised if there are any associated records * `:restrict_with_error` causes an error to be added to the owner if there are any associated objects diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 57945a256b..cb43781f52 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -43,7 +43,7 @@ Rails 4.0 no longer supports loading plugins from `vendor/plugins`. You must rep * Rails 4.0 has changed how orders get stacked in `ActiveRecord::Relation`. In previous versions of Rails, the new order was applied after the previously defined order. But this is no longer true. Check [Active Record Query guide](active_record_querying.html#ordering) for more information. -* Rails 4.0 has changed `serialized_attributes` and `attr_readonly` to class methods only. Now you shouldn't use instance methods, it's deprecated. You must change them, e.g. `self.serialized_attributes` to `self.class.serialized_attributes`. +* Rails 4.0 has changed `serialized_attributes` and `attr_readonly` to class methods only. You shouldn't use instance methods since it's now deprecated. You should change them to use class methods, e.g. `self.serialized_attributes` to `self.class.serialized_attributes`. * Rails 4.0 has removed `attr_accessible` and `attr_protected` feature in favor of Strong Parameters. You can use the [Protected Attributes gem](https://github.com/rails/protected_attributes) to a smoothly upgrade path. @@ -65,7 +65,7 @@ Rails 4.0 extracted Active Resource to its own gem. If you still need the featur ### Active Model -* Rails 4.0 has changed how errors attach with the `ActiveModel::Validations::ConfirmationValidator`. Now when confirmation validations fail the error will be attached to `:#{attribute}_confirmation` instead of `attribute`. +* Rails 4.0 has changed how errors attach with the `ActiveModel::Validations::ConfirmationValidator`. Now when confirmation validations fail, the error will be attached to `:#{attribute}_confirmation` instead of `attribute`. * Rails 4.0 has changed `ActiveModel::Serializers::JSON.include_root_in_json` default value to `false`. Now, Active Model Serializers and Active Record objects have the same default behaviour. This means that you can comment or remove the following option in the `config/initializers/wrap_parameters.rb` file: @@ -128,7 +128,7 @@ get 'こんにちは', controller: 'welcome', action: 'index' get "/" => "root#index" ``` -* Rails 4.0 has removed ActionDispatch::BestStandardsSupport middleware, !DOCTYPE html already triggers standards mode per http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx and ChromeFrame header has been moved to `config.action_dispatch.default_headers` +* Rails 4.0 has removed `ActionDispatch::BestStandardsSupport` middleware, `<!DOCTYPE html>` already triggers standards mode per http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx and ChromeFrame header has been moved to `config.action_dispatch.default_headers`. Remember you must also remove any references to the middleware from your application code, for example: diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 4f7cb8254f..420ed476b2 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -39,13 +39,13 @@ *Amparo Luna* * Fixes database.yml when creating a new rails application with '.' - Fix #8304 + Fixes #8304. *Jeremy W. Rowe* * Restore Rails::Engine::Railties#engines with deprecation to ensure compatibility with gems such as Thinking Sphinx - Fix #8551 + Fixes #8551. *Tim Raymond* @@ -119,7 +119,7 @@ * Environment name can be a start substring of the default environment names (production, development, test). For example: tes, pro, prod, dev, devel. - Fix #8628. + Fixes #8628. *Mykola Kyryk* @@ -129,7 +129,7 @@ * Quote column names in generates fixture files. This prevents conflicts with reserved YAML keywords such as 'yes' and 'no' - Fix #8612. + Fixes #8612. *Yves Senn* @@ -162,19 +162,19 @@ * Add `db` to list of folders included by `rake notes` and `rake notes:custom`. *Antonio Cangiano* * Engines with a dummy app include the rake tasks of dependencies in the app namespace. - Fix #8229 + Fixes #8229. *Yves Senn* * Add `sqlserver.yml` template file to satisfy `-d sqlserver` being passed to `rails new`. - Fix #6882 + Fixes #6882. *Robert Nesius* * Rake test:uncommitted finds git directory in ancestors *Nicolas Despres* * Add dummy app Rake tasks when `--skip-test-unit` and `--dummy-path` is passed to the plugin generator. - Fix #8121 + Fixes #8121. *Yves Senn* diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 25cc36ff5d..2417bdca21 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -46,10 +46,10 @@ module Rails # 6) Run config.before_initialize callbacks # 7) Run Railtie#initializer defined by railties, engines and application. # One by one, each engine sets up its load paths, routes and runs its config/initializers/* files. - # 9) Custom Railtie#initializers added by railties, engines and applications are executed - # 10) Build the middleware stack and run to_prepare callbacks - # 11) Run config.before_eager_load and eager_load! if eager_load is true - # 12) Run config.after_initialize callbacks + # 8) Custom Railtie#initializers added by railties, engines and applications are executed + # 9) Build the middleware stack and run to_prepare callbacks + # 10) Run config.before_eager_load and eager_load! if eager_load is true + # 11) Run config.after_initialize callbacks # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 5669fe6d64..c40eef145f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -24,10 +24,10 @@ <%- unless options.skip_sprockets? -%> # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier + config.assets.js_compressor = :uglifier # config.assets.css_compressor = :sass - # Whether to fallback to assets pipeline if a precompiled asset is missed. + # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Generate digests for assets URLs. diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 592bd73924..af495bb450 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -106,13 +106,13 @@ class FullStackConsoleTest < ActiveSupport::TestCase teardown_app end - def assert_output(expected, timeout = 0.2) + def assert_output(expected, timeout = 1) timeout = Time.now + timeout output = "" until output.include?(expected) || Time.now > timeout if IO.select([@master], [], [], 0.1) - output << @master.readpartial(100) + output << @master.read(1) end end @@ -138,7 +138,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase in: @slave, out: @slave, err: @slave ) - assert_output "> ", 5 + assert_output "> ", 30 pid end @@ -157,6 +157,6 @@ class FullStackConsoleTest < ActiveSupport::TestCase write_prompt "Post.transaction { Post.create; raise }" write_prompt "Post.count", "=> 0" ensure - kill pid + kill pid if pid end end diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index 6be4a5fe89..3c784b43be 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -58,10 +58,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_defaults_to_IRB - config = mock("config", console: nil) - app = mock("app", config: config) - app.expects(:load_console).returns(nil) - + app = build_app(console: nil) assert_equal IRB, Rails::Console.new(app).console end @@ -127,13 +124,15 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def app - @app ||= begin - config = mock("config", console: FakeConsole) - app = mock("app", config: config) - app.stubs(:sandbox=).returns(nil) - app.expects(:load_console) - app - end + @app ||= build_app(console: FakeConsole) + end + + def build_app(config) + config = mock("config", config) + app = mock("app", config: config) + app.stubs(:sandbox=).returns(nil) + app.expects(:load_console) + app end def parse_arguments(args) |