From a3dbb962fa81ba170aece567235a17e16770b8c8 Mon Sep 17 00:00:00 2001 From: Konstantin Shabanov Date: Tue, 5 Nov 2013 22:14:03 +0400 Subject: Don't load test env by default --- railties/lib/rails/test_unit/railtie.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index 75180ff978..878b9b7930 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,4 +1,4 @@ -if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? +if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^test(?::|$)/).any? ENV['RAILS_ENV'] ||= 'test' end -- cgit v1.2.3 From 9694f86de65e9162a6802a43cdbce9ccc85285b5 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Mon, 29 Jul 2013 09:22:14 +0530 Subject: [Active Record] Renamed private methods create_record and update_record This is to ensure that they are not accidentally called by the app code. They are renamed to _create_record and _update_record respectively. Closes #11645 --- .../associations/collection_association.rb | 8 ++++---- .../active_record/associations/singular_association.rb | 6 +++--- .../lib/active_record/attribute_methods/dirty.rb | 4 ++-- activerecord/lib/active_record/callbacks.rb | 4 ++-- activerecord/lib/active_record/locking/optimistic.rb | 2 +- activerecord/lib/active_record/persistence.rb | 8 ++++---- activerecord/lib/active_record/relation.rb | 2 +- activerecord/lib/active_record/timestamp.rb | 4 ++-- .../cases/associations/belongs_to_associations_test.rb | 18 ++++++++++++++++++ 9 files changed, 37 insertions(+), 19 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 03ca00fa70..b90c90c7c4 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -138,11 +138,11 @@ module ActiveRecord end def create(attributes = {}, &block) - create_record(attributes, &block) + _create_record(attributes, &block) end def create!(attributes = {}, &block) - create_record(attributes, true, &block) + _create_record(attributes, true, &block) end # Add +records+ to this association. Returns +self+ so method calls may @@ -452,13 +452,13 @@ module ActiveRecord persisted + memory end - def create_record(attributes, raise = false, &block) + def _create_record(attributes, raise = false, &block) unless owner.persisted? raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end if attributes.is_a?(Array) - attributes.collect { |attr| create_record(attr, raise, &block) } + attributes.collect { |attr| _create_record(attr, raise, &block) } else transaction do add_to_target(build_record(attributes)) do |record| diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb index 399aff378a..747bb5f1d6 100644 --- a/activerecord/lib/active_record/associations/singular_association.rb +++ b/activerecord/lib/active_record/associations/singular_association.rb @@ -18,11 +18,11 @@ module ActiveRecord end def create(attributes = {}, &block) - create_record(attributes, &block) + _create_record(attributes, &block) end def create!(attributes = {}, &block) - create_record(attributes, true, &block) + _create_record(attributes, true, &block) end def build(attributes = {}) @@ -52,7 +52,7 @@ module ActiveRecord replace(record) end - def create_record(attributes, raise_error = false) + def _create_record(attributes, raise_error = false) record = build_record(attributes) yield(record) if block_given? saved = record.save diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 8a1b199997..99070f127b 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -79,11 +79,11 @@ module ActiveRecord end end - def update_record(*) + def _update_record(*) partial_writes? ? super(keys_for_partial_write) : super end - def create_record(*) + def _create_record(*) partial_writes? ? super(keys_for_partial_write) : super end diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 35f19f0bc0..5955673b42 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -302,11 +302,11 @@ module ActiveRecord run_callbacks(:save) { super } end - def create_record #:nodoc: + def _create_record #:nodoc: run_callbacks(:create) { super } end - def update_record(*) #:nodoc: + def _update_record(*) #:nodoc: run_callbacks(:update) { super } end end diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 6f54729b3c..4d63b04d9f 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -66,7 +66,7 @@ module ActiveRecord send(lock_col + '=', previous_lock_value + 1) end - def update_record(attribute_names = @attributes.keys) #:nodoc: + def _update_record(attribute_names = @attributes.keys) #:nodoc: return super unless locking_enabled? return 0 if attribute_names.empty? diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index b1b35ed940..063b1d1bd0 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -477,24 +477,24 @@ module ActiveRecord def create_or_update raise ReadOnlyRecord if readonly? - result = new_record? ? create_record : update_record + result = new_record? ? _create_record : _update_record result != false end # Updates the associated record with values matching those of the instance attributes. # Returns the number of affected rows. - def update_record(attribute_names = @attributes.keys) + def _update_record(attribute_names = @attributes.keys) attributes_values = arel_attributes_with_values_for_update(attribute_names) if attributes_values.empty? 0 else - self.class.unscoped.update_record attributes_values, id, id_was + self.class.unscoped._update_record attributes_values, id, id_was end end # Creates a record with values matching those of the instance attributes # and returns its id. - def create_record(attribute_names = @attributes.keys) + def _create_record(attribute_names = @attributes.keys) attributes_values = arel_attributes_with_values_for_create(attribute_names) new_id = self.class.unscoped.insert attributes_values diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index fb213dc6f7..447042254d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -70,7 +70,7 @@ module ActiveRecord binds) end - def update_record(values, id, id_was) # :nodoc: + def _update_record(values, id, id_was) # :nodoc: substitutes, binds = substitute_values values um = @klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key) diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index 7178bed560..6c30ccab72 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -43,7 +43,7 @@ module ActiveRecord private - def create_record + def _create_record if self.record_timestamps current_time = current_time_from_proper_timezone @@ -57,7 +57,7 @@ module ActiveRecord super end - def update_record(*args) + def _update_record(*args) if should_record_timestamps? current_time = current_time_from_proper_timezone diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 9340bc0a83..d172ee2e7a 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -863,4 +863,22 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end end end + + test 'belongs_to works with model name Record' do + Record = Class.new(ActiveRecord::Base) do + connection.create_table :records + end + + Foo = Class.new(ActiveRecord::Base) do + connection.create_table :foos do |t| + t.belongs_to :record + end + + belongs_to :record + end + + record = Record.create! + Foo.create! record: record + assert_equal 1, Foo.count + end end -- cgit v1.2.3 From 70a5e5638bfd3b2543bb9d4805cbefec84b6b1ce Mon Sep 17 00:00:00 2001 From: Matt Jones Date: Fri, 21 Feb 2014 17:58:40 -0500 Subject: Pass a base relation to build_default_scope when joining This allows the default scope to be built using the current table alias. Resolves #12770 --- .../associations/join_dependency/join_association.rb | 2 +- activerecord/lib/active_record/scoping/default.rb | 6 +++--- .../test/cases/associations/inner_join_association_test.rb | 9 +++++++++ activerecord/test/models/category.rb | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index cee3c9999f..1d923ecc09 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -54,7 +54,7 @@ module ActiveRecord end scope_chain_index += 1 - scope_chain_items.concat [klass.send(:build_default_scope)].compact + scope_chain_items.concat [klass.send(:build_default_scope, ActiveRecord::Relation.create(klass, table))].compact rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right| left.merge right diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb index 01fec31544..8ca5e8d6f6 100644 --- a/activerecord/lib/active_record/scoping/default.rb +++ b/activerecord/lib/active_record/scoping/default.rb @@ -93,14 +93,14 @@ module ActiveRecord self.default_scopes += [scope] end - def build_default_scope # :nodoc: + def build_default_scope(base_rel = relation) # :nodoc: if !Base.is_a?(method(:default_scope).owner) # The user has defined their own default scope method, so call that evaluate_default_scope { default_scope } elsif default_scopes.any? evaluate_default_scope do - default_scopes.inject(relation) do |default_scope, scope| - default_scope.merge(unscoped { scope.call }) + default_scopes.inject(base_rel) do |default_scope, scope| + default_scope.merge(base_rel.scoping { scope.call }) end end end diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index a9efa6d86a..b23517b2f9 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -117,4 +117,13 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase assert_equal [author], Author.where(id: author).joins(:special_categorizations) end + + test "the default scope of the target is correctly aliased when joining associations" do + author = Author.create! name: "Jon" + author.categories.create! name: 'Not Special' + author.special_categories.create! name: 'Special' + + categories = author.categories.includes(:special_categorizations).references(:special_categorizations).to_a + assert_equal 2, categories.size + end end diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb index 7da39a8e33..272223e1d8 100644 --- a/activerecord/test/models/category.rb +++ b/activerecord/test/models/category.rb @@ -22,6 +22,7 @@ class Category < ActiveRecord::Base end has_many :categorizations + has_many :special_categorizations has_many :post_comments, :through => :posts, :source => :comments has_many :authors, :through => :categorizations -- cgit v1.2.3 From 7ea0a50126a5b8f988fcf1c3fb0c57bdb52918c7 Mon Sep 17 00:00:00 2001 From: Rashmi Yadav Date: Sat, 8 Mar 2014 20:23:15 +0100 Subject: Updating select helper doc [ci skip] --- guides/source/form_helpers.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 455dc7bebe..205e0f6b62 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -474,6 +474,16 @@ As with other helpers, if you were to use the `select` helper on a form builder <%= f.select(:city_id, ...) %> ``` +You can also pass a block to `select` helper: + +```erb +<%= f.select(:city_id) do %> + <% [['Lisbon', 1], ['Madrid', 2]].each do |c| -%> + <%= content_tag(:option, c.first, value: c.last) %> + <% end %> +<% end %> +``` + WARNING: If you are using `select` (or similar helpers such as `collection_select`, `select_tag`) to set a `belongs_to` association you must pass the name of the foreign key (in the example above `city_id`), not the name of association itself. If you specify `city` instead of `city_id` Active Record will raise an error along the lines of ` ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) ` when you pass the `params` hash to `Person.new` or `update`. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential security ramifications of allowing users to edit foreign keys directly. ### Option Tags from a Collection of Arbitrary Objects -- cgit v1.2.3 From cc4c6d405df8d4339112b44670dcce1b52e93f42 Mon Sep 17 00:00:00 2001 From: Steven Harman Date: Fri, 14 Mar 2014 12:09:26 -0400 Subject: Fix misspelling in references docs --- activerecord/lib/active_record/relation/query_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 8c005a7222..3a5b3116eb 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -168,7 +168,7 @@ module ActiveRecord # Use to indicate that the given +table_names+ are referenced by an SQL string, # and should therefore be JOINed in any query rather than loaded separately. - # This method only works in conjuction with +includes+. + # This method only works in conjunction with +includes+. # See #includes for more details. # # User.includes(:posts).where("posts.name = 'foo'") -- cgit v1.2.3 From ea3a73e720b5ffed6b6220dc9ce92776804cb06f Mon Sep 17 00:00:00 2001 From: Washington Luiz Date: Fri, 14 Mar 2014 22:20:13 -0300 Subject: Still touch associations when theres no timestamp Prior to Rails 4.0.4 when touching a object which doesn't have timestamp attributes (updated_at / updated_on) rails would still touch all associations. After 73ba2c14cd7d7dfb2d132b18c47ade995401736f it updates associations but rollsback because `touch` would return nil since there's no timestamp attribute --- activerecord/lib/active_record/persistence.rb | 2 ++ .../test/cases/associations/belongs_to_associations_test.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 4e63206cf4..905289f398 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -452,6 +452,8 @@ module ActiveRecord changed_attributes.except!(*changes.keys) primary_key = self.class.primary_key self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1 + else + true end end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 9340bc0a83..5c9ec3104f 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -340,6 +340,17 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_queries(1) { line_item.touch } end + def test_belongs_to_with_touch_option_on_touch_without_updated_at_attributes + assert !LineItem.column_names.include?("updated_at") + + line_item = LineItem.create! + invoice = Invoice.create!(line_items: [line_item]) + initial = invoice.updated_at + line_item.touch + + refute_equal initial, invoice.reload.updated_at + end + def test_belongs_to_with_touch_option_on_touch_and_removed_parent line_item = LineItem.create! Invoice.create!(line_items: [line_item]) -- cgit v1.2.3 From 6c821073f3eb0cb4acec8ad98fc54a25fd5fe6ce Mon Sep 17 00:00:00 2001 From: Earl St Sauver Date: Mon, 17 Mar 2014 11:28:57 -0700 Subject: Update documentation on group method to indicate it takes an array The group method also takes an array, however this isn't immediately clear by reading the source since it delegates this method. If you trace it back to the AREL building you can see that it does support an array. Shoutout to @betovelandia for pointing this out. --- activerecord/lib/active_record/relation/query_methods.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 3a5b3116eb..eff10d3575 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -261,6 +261,10 @@ module ActiveRecord # # User.group('name AS grouped_name, age') # => [#, #, #] + # + # Passing in an array of attributes to group by is also supported. + # User.select([:id, :first_name]).group(:id, :first_name).first(3) + # => [#, #, #] def group(*args) check_if_method_has_arguments!(:group, args) spawn.group!(*args) -- cgit v1.2.3 From 9632919b0ca6423ae46fbb1c079ccdeb8353ecab Mon Sep 17 00:00:00 2001 From: Earl St Sauver Date: Thu, 20 Mar 2014 14:59:39 -0700 Subject: Mention required glob param name in match docs for mapper THe match documentation doesn't mention any requirement of the parameter name requirement for matches. However, including a bare glob character without a variable assignment causes a parse error. --- actionpack/lib/action_dispatch/routing/mapper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0b762aa9a4..833573b41a 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -357,6 +357,10 @@ module ActionDispatch # # params[:category] = 'rock/classic' # # params[:title] = 'stairway-to-heaven' # + # To match a wildcard parameter, it must have a name assigned to it. + # Without a variable name to attach the glob parameter to, the route + # can't be parsed. + # # When a pattern points to an internal route, the route's +:action+ and # +:controller+ should be set in options or hash shorthand. Examples: # -- cgit v1.2.3 From e94e6c27af495a2460c811bb506459f1428dec6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Mar 2014 15:09:48 -0300 Subject: Revert "Merge pull request #8313 from alan/only_save_changed_has_one_objects" This reverts commit 6e3ab3e15faf782f6a937ccf5574a4fb63e3e353, reversing changes made to 39e07b64ce3f4bb55e60ba0266e677f8e4f4893a. Conflicts: activerecord/CHANGELOG.md activerecord/test/cases/autosave_association_test.rb --- activerecord/CHANGELOG.md | 12 ++++++------ activerecord/lib/active_record/autosave_association.rb | 5 ++--- activerecord/test/cases/autosave_association_test.rb | 13 ------------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index bb2dbba860..6e77493de9 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Save `has_one` association even if the record doesn't changed. + + Fixes #14407. + + *Rafael Mendonça França* + * Use singular table name in generated migrations when `ActiveRecord::Base.pluralize_table_names` is `false`. @@ -76,12 +82,6 @@ *Troy Kruthoff*, *Lachlan Sylvester* -* Only save has_one associations if record has changes. - Previously after save related callbacks, such as `#after_commit`, were triggered when the has_one - object did not get saved to the db. - - *Alan Kennedy* - * Allow strings to specify the `#order` value. Example: diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 213b72b933..e9622ca0c1 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -377,16 +377,15 @@ module ActiveRecord def save_has_one_association(reflection) association = association_instance_get(reflection.name) record = association && association.load_target - if record && !record.destroyed? autosave = reflection.options[:autosave] if autosave && record.marked_for_destruction? record.destroy - elsif autosave != false + else key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id + if autosave != false && (autosave || new_record? || record_changed?(reflection, record, key)) - if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key) unless reflection.through_reflection record[reflection.foreign_key] = key end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 09892d50ba..f7584c3a51 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -683,23 +683,10 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end end - @ship.pirate.catchphrase = "Changed Catchphrase" - assert_raise(RuntimeError) { assert !@pirate.save } assert_not_nil @pirate.reload.ship end - def test_should_save_changed_has_one_changed_object_if_child_is_saved - @pirate.ship.name = "NewName" - assert @pirate.save - assert_equal "NewName", @pirate.ship.reload.name - end - - def test_should_not_save_changed_has_one_unchanged_object_if_child_is_saved - @pirate.ship.expects(:save).never - assert @pirate.save - end - # belongs_to def test_should_destroy_a_parent_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal assert !@ship.pirate.marked_for_destruction? -- cgit v1.2.3 From ade741e113928b6ee4b376ee5d60e6813ecc35c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Mar 2014 15:14:52 -0300 Subject: Use rails convetions --- activerecord/test/cases/associations/belongs_to_associations_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 7994f76d08..a65f2da7a0 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -341,14 +341,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_belongs_to_with_touch_option_on_touch_without_updated_at_attributes - assert !LineItem.column_names.include?("updated_at") + assert_not LineItem.column_names.include?("updated_at") line_item = LineItem.create! invoice = Invoice.create!(line_items: [line_item]) initial = invoice.updated_at line_item.touch - refute_equal initial, invoice.reload.updated_at + assert_not_equal initial, invoice.reload.updated_at end def test_belongs_to_with_touch_option_on_touch_and_removed_parent -- cgit v1.2.3 From ce0df82057ac31df0e620cf4a303d3428aa93020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Mar 2014 15:35:06 -0300 Subject: Fix the update_versions release task --- Rakefile | 28 +--------------------------- tasks/release.rb | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 49 deletions(-) diff --git a/Rakefile b/Rakefile index 5585280589..aae59b8ecc 100644 --- a/Rakefile +++ b/Rakefile @@ -46,33 +46,7 @@ else end desc 'Bump all versions to match version.rb' -task :update_versions do - require File.dirname(__FILE__) + "/version" - - File.open("RAILS_VERSION", "w") do |f| - f.puts Rails::VERSION::STRING - end - - constants = { - "activesupport" => "ActiveSupport", - "activemodel" => "ActiveModel", - "actionpack" => "ActionPack", - "actionview" => "ActionView", - "actionmailer" => "ActionMailer", - "activerecord" => "ActiveRecord", - "railties" => "Rails" - } - - version_file = File.read("version.rb") - - PROJECTS.each do |project| - Dir["#{project}/lib/*/gem_version.rb"].each do |file| - File.open(file, "w") do |f| - f.write version_file.gsub(/Rails/, constants[project]) - end - end - end -end +task :update_versions => "all:update_versions" # We have a webhook configured in GitHub that gets invoked after pushes. # This hook triggers the following tasks: diff --git a/tasks/release.rb b/tasks/release.rb index a55cb68a47..849117884c 100644 --- a/tasks/release.rb +++ b/tasks/release.rb @@ -15,38 +15,37 @@ directory "pkg" rm_f gem end - task :update_version_rb do + task :update_versions do glob = root.dup - glob << "/#{framework}/lib/*" unless framework == "rails" - glob << "/version.rb" + if framework == "rails" + glob << "/version.rb" + else + glob << "/#{framework}/lib/*" + glob << "/gem_version.rb" + end file = Dir[glob].first ruby = File.read(file) - if framework == "rails" || framework == "railties" - major, minor, tiny, pre = version.split('.') - pre = pre ? pre.inspect : "nil" + major, minor, tiny, pre = version.split('.') + pre = pre ? pre.inspect : "nil" - ruby.gsub!(/^(\s*)MAJOR(\s*)= .*?$/, "\\1MAJOR = #{major}") - raise "Could not insert MAJOR in #{file}" unless $1 + ruby.gsub!(/^(\s*)MAJOR(\s*)= .*?$/, "\\1MAJOR = #{major}") + raise "Could not insert MAJOR in #{file}" unless $1 - ruby.gsub!(/^(\s*)MINOR(\s*)= .*?$/, "\\1MINOR = #{minor}") - raise "Could not insert MINOR in #{file}" unless $1 + ruby.gsub!(/^(\s*)MINOR(\s*)= .*?$/, "\\1MINOR = #{minor}") + raise "Could not insert MINOR in #{file}" unless $1 - ruby.gsub!(/^(\s*)TINY(\s*)= .*?$/, "\\1TINY = #{tiny}") - raise "Could not insert TINY in #{file}" unless $1 + ruby.gsub!(/^(\s*)TINY(\s*)= .*?$/, "\\1TINY = #{tiny}") + raise "Could not insert TINY in #{file}" unless $1 - ruby.gsub!(/^(\s*)PRE(\s*)= .*?$/, "\\1PRE = #{pre}") - raise "Could not insert PRE in #{file}" unless $1 - else - ruby.gsub!(/^(\s*)Gem::Version\.new .*?$/, "\\1Gem::Version.new \"#{version}\"") - raise "Could not insert Gem::Version in #{file}" unless $1 - end + ruby.gsub!(/^(\s*)PRE(\s*)= .*?$/, "\\1PRE = #{pre}") + raise "Could not insert PRE in #{file}" unless $1 File.open(file, 'w') { |f| f.write ruby } end - task gem => %w(update_version_rb pkg) do + task gem => %w(update_versions pkg) do cmd = "" cmd << "cd #{framework} && " unless framework == "rails" cmd << "gem build #{gemspec} && mv #{framework}-#{version}.gem #{root}/pkg/" @@ -93,9 +92,10 @@ namespace :changelog do end namespace :all do - task :build => FRAMEWORKS.map { |f| "#{f}:build" } + ['rails:build'] - task :install => FRAMEWORKS.map { |f| "#{f}:install" } + ['rails:install'] - task :push => FRAMEWORKS.map { |f| "#{f}:push" } + ['rails:push'] + task :build => FRAMEWORKS.map { |f| "#{f}:build" } + ['rails:build'] + task :update_versions => FRAMEWORKS.map { |f| "#{f}:update_versions" } + ['rails:update_versions'] + task :install => FRAMEWORKS.map { |f| "#{f}:install" } + ['rails:install'] + task :push => FRAMEWORKS.map { |f| "#{f}:push" } + ['rails:push'] task :ensure_clean_state do unless `git status -s | grep -v RAILS_VERSION`.strip.empty? -- cgit v1.2.3 From 470108b6e95a32e017ba3790d5701d8c8e91bf29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Mar 2014 15:36:28 -0300 Subject: Fix task comment to match which file should be changed [ci skip] --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index aae59b8ecc..0737afd089 100644 --- a/Rakefile +++ b/Rakefile @@ -45,7 +45,7 @@ else Rails::API::StableTask.new('rdoc') end -desc 'Bump all versions to match version.rb' +desc 'Bump all versions to match RAILS_VERSION' task :update_versions => "all:update_versions" # We have a webhook configured in GitHub that gets invoked after pushes. -- cgit v1.2.3 From afa148a4f0ac5e2a446b5fe87881a130e8a24f3d Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Tue, 21 Jan 2014 16:56:53 -0700 Subject: create indexes inline in CREATE TABLE for MySQL This is important, because adding an index on a temporary table after it has been created would commit the transaction Conflicts: activerecord/CHANGELOG.md --- .../abstract/schema_statements.rb | 21 ++++++++++----------- .../connection_adapters/abstract_adapter.rb | 6 ++++++ .../connection_adapters/abstract_mysql_adapter.rb | 20 ++++++++++++++++++++ .../test/cases/adapters/mysql/active_schema_test.rb | 11 +++++++++++ .../cases/adapters/mysql2/active_schema_test.rb | 11 +++++++++++ 5 files changed, 58 insertions(+), 11 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 7f530ec5e4..59210c345f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -186,24 +186,23 @@ module ActiveRecord def create_table(table_name, options = {}) td = create_table_definition table_name, options[:temporary], options[:options], options[:as] - if !options[:as] - unless options[:id] == false - pk = options.fetch(:primary_key) { - Base.get_primary_key table_name.to_s.singularize - } - - td.primary_key pk, options.fetch(:id, :primary_key), options - end + unless options[:id] == false || options[:as] + pk = options.fetch(:primary_key) { + Base.get_primary_key table_name.to_s.singularize + } - yield td if block_given? + td.primary_key pk, options.fetch(:id, :primary_key), options end + yield td if block_given? + if options[:force] && table_exists?(table_name) drop_table(table_name, options) end - execute schema_creation.accept td - td.indexes.each_pair { |c,o| add_index table_name, c, o } + result = execute schema_creation.accept td + td.indexes.each_pair { |c,o| add_index table_name, c, o } unless supports_indexes_in_create? + result end # Creates a new join table with the name created using the lexical order of the first two diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index c7e5a18f02..543eeb5740 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -217,6 +217,12 @@ module ActiveRecord false end + # Does this adapter support creating indexes in the same statement as + # creating the table? As of this writing, only mysql does. + def supports_indexes_in_create? + false + end + # This is meant to be implemented by the adapters that support extensions def disable_extension(name) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 9a819720f7..96c7d5d7eb 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -6,6 +6,17 @@ module ActiveRecord include Savepoints class SchemaCreation < AbstractAdapter::SchemaCreation + def visit_TableDefinition(o) + create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE " + create_sql << "#{quote_table_name(o.name)} " + statements = [] + statements.concat(o.columns.map { |c| accept c }) + statements.concat(o.indexes.map { |(column_name, options)| index_in_create(o.name, column_name, options) }) + create_sql << "(#{statements.join(', ')}) " + create_sql << "#{o.options}" + create_sql << " AS #{@conn.to_sql(o.as)}" if o.as + create_sql + end def visit_AddColumn(o) add_column_position!(super, column_options(o)) @@ -29,6 +40,11 @@ module ActiveRecord end sql end + + def index_in_create(table_name, column_name, options) + index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.send(:add_index_options, table_name, column_name, options) + "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}".gsub(' ', ' ').strip + end end def schema_creation @@ -225,6 +241,10 @@ module ActiveRecord version[0] >= 5 end + def supports_indexes_in_create? + true + end + def native_database_types NATIVE_DATABASE_TYPES end diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index e77138eb1d..072aa65000 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -116,6 +116,17 @@ class ActiveSchemaTest < ActiveRecord::TestCase end end + def test_indexes_in_create + begin + ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false) + expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| + t.index :zip + end + assert_equal expected, actual + end + end + private def with_real_execute ActiveRecord::Base.connection.singleton_class.class_eval do diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 7905edaf83..91d880e5ae 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -116,6 +116,17 @@ class ActiveSchemaTest < ActiveRecord::TestCase end end + def test_indexes_in_create + begin + ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false) + expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| + t.index :zip + end + assert_equal expected, actual + end + end + private def with_real_execute ActiveRecord::Base.connection.singleton_class.class_eval do -- cgit v1.2.3 From 63c94efccb20c0b398dd90c0d209d6894eb22d92 Mon Sep 17 00:00:00 2001 From: Steve Rice Date: Tue, 25 Mar 2014 21:13:29 -0700 Subject: Fixes bugs for using indexes in CREATE TABLE by adding checks for table existence Also: - updates tests by stubbing table_exists? method - adds entry for creating indexes in CREATE TABLE to changelog --- activerecord/CHANGELOG.md | 15 +++++++++++++++ .../connection_adapters/abstract/schema_statements.rb | 2 +- .../connection_adapters/abstract_mysql_adapter.rb | 2 +- .../test/cases/adapters/mysql/active_schema_test.rb | 6 ++++-- .../test/cases/adapters/mysql2/active_schema_test.rb | 6 ++++-- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 6e77493de9..ccd07ce248 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,18 @@ +* Create indexes inline in CREATE TABLE for MySQL + + This is important, because adding an index on a temporary table after it has been created + would commit the transaction. + It also allows creating and dropping indexed tables with fewer queries and fewer permissions required. + + Example: + + create_table :temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query" do |t| + t.index :zip + end + # => CREATE TEMPORARY TABLE temp (INDEX (zip)) AS SELECT id, name, zip FROM a_really_complicated_query + + *Cody Cutrer*, *Steve Rice* + * Save `has_one` association even if the record doesn't changed. Fixes #14407. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 59210c345f..23404a5c48 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -795,7 +795,7 @@ module ActiveRecord if index_name.length > max_index_length raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" end - if index_name_exists?(table_name, index_name, false) + if table_exists?(table_name) && index_name_exists?(table_name, index_name, false) raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" end index_columns = quoted_columns_for_index(column_names, options).join(", ") diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 96c7d5d7eb..a1748c9261 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -12,7 +12,7 @@ module ActiveRecord statements = [] statements.concat(o.columns.map { |c| accept c }) statements.concat(o.indexes.map { |(column_name, options)| index_in_create(o.name, column_name, options) }) - create_sql << "(#{statements.join(', ')}) " + create_sql << "(#{statements.join(', ')}) " if statements.present? create_sql << "#{o.options}" create_sql << " AS #{@conn.to_sql(o.as)}" if o.as create_sql diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index 072aa65000..35681fb5ae 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -17,7 +17,8 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_index - # add_index calls index_name_exists? which can't work since execute is stubbed + # add_index calls table_exists? and index_name_exists? which can't work since execute is stubbed + def (ActiveRecord::Base.connection).table_exists?(*); true; end def (ActiveRecord::Base.connection).index_name_exists?(*); false; end expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " @@ -118,7 +119,8 @@ class ActiveSchemaTest < ActiveRecord::TestCase def test_indexes_in_create begin - ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false) + ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) + ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| t.index :zip diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 91d880e5ae..925b9c1bd1 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -17,7 +17,8 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_index - # add_index calls index_name_exists? which can't work since execute is stubbed + # add_index calls table_exists? and index_name_exists? which can't work since execute is stubbed + def (ActiveRecord::Base.connection).table_exists?(*); true; end def (ActiveRecord::Base.connection).index_name_exists?(*); false; end expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " @@ -118,7 +119,8 @@ class ActiveSchemaTest < ActiveRecord::TestCase def test_indexes_in_create begin - ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false) + ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) + ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| t.index :zip -- cgit v1.2.3 From dcda6e32b4496f11bf6e43fddc5772376ac0f9b2 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Wed, 26 Mar 2014 09:06:31 +0100 Subject: link to "Schema migration" Wikipedia page. Closes #14479. [ci skip] --- guides/source/migrations.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/guides/source/migrations.md b/guides/source/migrations.md index 05443d5a5f..bfee55a95d 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -18,9 +18,10 @@ After reading this guide, you will know: Migration Overview ------------------ -Migrations are a convenient way to alter your database schema over time in a -consistent and easy way. They use a Ruby DSL so that you don't have to write -SQL by hand, allowing your schema and changes to be database independent. +Migrations are a convenient way to +[alter your database schema over time](http://en.wikipedia.org/wiki/Schema_migration) +in a consistent and easy way. They use a Ruby DSL so that you don't have to +write SQL by hand, allowing your schema and changes to be database independent. You can think of each migration as being a new 'version' of the database. A schema starts off with nothing in it, and each migration modifies it to add or -- cgit v1.2.3 From c7ab4fc4e2844294f26b07ec5e69fee2708b0f8a Mon Sep 17 00:00:00 2001 From: Juanito Fatas Date: Thu, 27 Mar 2014 01:39:58 +0800 Subject: [ci skip] Fix Pull Request URL in 4.1 release note. --- guides/source/4_1_release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md index f3b93991fc..822943d81e 100644 --- a/guides/source/4_1_release_notes.md +++ b/guides/source/4_1_release_notes.md @@ -711,7 +711,7 @@ for detailed changes. * Default the new `I18n.enforce_available_locales` config to `true`, meaning `I18n` will make sure that all locales passed to it must be declared in the `available_locales` - list. ([Pull Request](https://github.com/rails/rails/commit/8e21ae37ad9fef6b7393a84f9b5f2e18a831e49a)) + list. ([Pull Request](https://github.com/rails/rails/pull/13341)) * Introduce `Module#concerning`: a natural, low-ceremony way to separate responsibilities within a -- cgit v1.2.3 From 6af07c27ae65dfaf0d42a2741544915459efe67a Mon Sep 17 00:00:00 2001 From: Boris Kuznetsov Date: Thu, 30 Jan 2014 18:33:49 +0400 Subject: Append link to bad code to backtrace when exception is SyntaxError --- actionpack/CHANGELOG.md | 4 +++ .../middleware/exception_wrapper.rb | 8 +++++ actionpack/test/dispatch/debug_exceptions_test.rb | 35 ++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index fe5b38d29f..e70e0b5fa7 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,7 @@ +* Append link to bad code to backtrace when exception is SyntaxError. + + *Boris Kuznetsov* + * Swapped the parameters of assert_equal in `assert_select` so that the proper values were printed correctly diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 377f05c982..2326bb043a 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -32,6 +32,8 @@ module ActionDispatch def initialize(env, exception) @env = env @exception = original_exception(exception) + + expand_backtrace if exception.is_a?(SyntaxError) || exception.try(:original_exception).try(:is_a?, SyntaxError) end def rescue_template @@ -104,5 +106,11 @@ module ActionDispatch end end end + + def expand_backtrace + @exception.backtrace.unshift( + @exception.to_s.split("\n") + ).flatten! + end end end diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 3045a07ad6..0dba651139 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -43,6 +43,19 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest raise ActionController::UrlGenerationError, "No route matches" when "/parameter_missing" raise ActionController::ParameterMissing, :missing_param_key + when "/original_syntax_error" + eval 'broke_syntax =' # `eval` need for raise native SyntaxError at runtime + when "/syntax_error_into_view" + begin + eval 'broke_syntax =' + rescue Exception => e + template = ActionView::Template.new(File.read(__FILE__), + __FILE__, + ActionView::Template::Handlers::Raw.new, + {}) + raise ActionView::Template::Error.new(template, e) + end + else raise "puke!" end @@ -242,4 +255,26 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest get "/", {}, env assert_operator((output.rewind && output.read).lines.count, :>, 10) end + + test 'display backtrace when error type is SyntaxError' do + @app = DevelopmentApp + + get '/original_syntax_error', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new} + + assert_response 500 + assert_select '#Application-Trace' do + assert_select 'pre code', /\(eval\):1: syntax error, unexpected/ + end + end + + test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do + @app = DevelopmentApp + + get '/syntax_error_into_view', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new} + + assert_response 500 + assert_select '#Application-Trace' do + assert_select 'pre code', /\(eval\):1: syntax error, unexpected/ + end + end end -- cgit v1.2.3 From baf62e531686ee157746d239037be121f8191275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 17:37:26 -0300 Subject: Invert the conditionals to make easier to read Also improve some of the code conventions --- .../connection_adapters/abstract/schema_statements.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 23404a5c48..b59d263dfa 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -186,10 +186,10 @@ module ActiveRecord def create_table(table_name, options = {}) td = create_table_definition table_name, options[:temporary], options[:options], options[:as] - unless options[:id] == false || options[:as] - pk = options.fetch(:primary_key) { + if options[:id] != false && !options[:as] + pk = options.fetch(:primary_key) do Base.get_primary_key table_name.to_s.singularize - } + end td.primary_key pk, options.fetch(:id, :primary_key), options end @@ -201,7 +201,7 @@ module ActiveRecord end result = execute schema_creation.accept td - td.indexes.each_pair { |c,o| add_index table_name, c, o } unless supports_indexes_in_create? + td.indexes.each_pair { |c, o| add_index(table_name, c, o) } unless supports_indexes_in_create? result end -- cgit v1.2.3 From fb743941d51475e416f4b4d1ecd8b3a91e501cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 19:15:57 -0300 Subject: Remove unneeded comments about feature support on the adapters These comments will likely be outdated with time and doesn't include any information that can't be found in the adapters --- .../connection_adapters/abstract_adapter.rb | 29 +++++++--------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 543eeb5740..05e9b03e3a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -146,28 +146,24 @@ module ActiveRecord 'Abstract' end - # Does this adapter support migrations? Backend specific, as the - # abstract adapter always returns +false+. + # Does this adapter support migrations? def supports_migrations? false end # Can this adapter determine the primary key for tables not attached - # to an Active Record class, such as join tables? Backend specific, as - # the abstract adapter always returns +false+. + # to an Active Record class, such as join tables? def supports_primary_key? false end - # Does this adapter support using DISTINCT within COUNT? This is +true+ - # for all adapters except sqlite. + # Does this adapter support using DISTINCT within COUNT? def supports_count_distinct? true end # Does this adapter support DDL rollbacks in transactions? That is, would - # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL, - # SQL Server, and others support this. MySQL and others do not. + # CREATE TABLE or ALTER TABLE get rolled back by a transaction? def supports_ddl_transactions? false end @@ -176,8 +172,7 @@ module ActiveRecord false end - # Does this adapter support savepoints? PostgreSQL and MySQL do, - # SQLite < 3.6.8 does not. + # Does this adapter support savepoints? def supports_savepoints? false end @@ -185,7 +180,6 @@ module ActiveRecord # Should primary key values be selected from their corresponding # sequence before the insert statement? If true, next_sequence_value # is called before each insert to set the record's primary key. - # This is false for all adapters but Firebird. def prefetch_primary_key?(table_name = nil) false end @@ -200,8 +194,7 @@ module ActiveRecord false end - # Does this adapter support explain? As of this writing sqlite3, - # mysql2, and postgresql are the only ones that do. + # Does this adapter support explain? def supports_explain? false end @@ -211,14 +204,13 @@ module ActiveRecord false end - # Does this adapter support database extensions? As of this writing only - # postgresql does. + # Does this adapter support database extensions? def supports_extensions? false end # Does this adapter support creating indexes in the same statement as - # creating the table? As of this writing, only mysql does. + # creating the table? def supports_indexes_in_create? false end @@ -231,14 +223,12 @@ module ActiveRecord def enable_extension(name) end - # A list of extensions, to be filled in by adapters that support them. At - # the moment only postgresql does. + # A list of extensions, to be filled in by adapters that support them. def extensions [] end # A list of index algorithms, to be filled by adapters that support them. - # MySQL and PostgreSQL have support for them right now. def index_algorithms {} end @@ -299,7 +289,6 @@ module ActiveRecord end # Returns true if its required to reload the connection between requests for development mode. - # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite. def requires_reloading? false end -- cgit v1.2.3 From 4e2ca9b23fcaa98f4ef375a3a6d8eee579baec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:02:27 -0300 Subject: Improve the method * cache `o.name` value * Avoid extra `concat` call * Avoid extra `<<` call --- .../connection_adapters/abstract_mysql_adapter.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index a1748c9261..35931d864f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -7,11 +7,12 @@ module ActiveRecord class SchemaCreation < AbstractAdapter::SchemaCreation def visit_TableDefinition(o) - create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE " - create_sql << "#{quote_table_name(o.name)} " - statements = [] - statements.concat(o.columns.map { |c| accept c }) - statements.concat(o.indexes.map { |(column_name, options)| index_in_create(o.name, column_name, options) }) + name = o.name + create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} " + + statements = o.columns.map { |c| accept c } + statements.concat(o.indexes.map { |column_name, options| index_in_create(name, column_name, options) }) + create_sql << "(#{statements.join(', ')}) " if statements.present? create_sql << "#{o.options}" create_sql << " AS #{@conn.to_sql(o.as)}" if o.as -- cgit v1.2.3 From e1a41fb9fc9eaedc3c220c8844aa04074746fa84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:04:12 -0300 Subject: Make method private --- .../connection_adapters/abstract_mysql_adapter.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 35931d864f..c74b916502 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -6,6 +6,12 @@ module ActiveRecord include Savepoints class SchemaCreation < AbstractAdapter::SchemaCreation + def visit_AddColumn(o) + add_column_position!(super, column_options(o)) + end + + private + def visit_TableDefinition(o) name = o.name create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} " @@ -19,11 +25,6 @@ module ActiveRecord create_sql end - def visit_AddColumn(o) - add_column_position!(super, column_options(o)) - end - - private def visit_ChangeColumnDefinition(o) column = o.column options = o.options -- cgit v1.2.3 From ee7db778afb7c867c4cf67777e19667431284975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:04:55 -0300 Subject: Don't use send when we own the method --- .../abstract/schema_statements.rb | 68 +++++++++++----------- .../connection_adapters/abstract_mysql_adapter.rb | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index b59d263dfa..aa99822389 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -739,6 +739,40 @@ module ActiveRecord Table.new(table_name, base) end + def add_index_options(table_name, column_name, options = {}) #:nodoc: + column_names = Array(column_name) + index_name = index_name(table_name, column: column_names) + + options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) + + index_type = options[:unique] ? "UNIQUE" : "" + index_type = options[:type].to_s if options.key?(:type) + index_name = options[:name].to_s if options.key?(:name) + max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length + + if options.key?(:algorithm) + algorithm = index_algorithms.fetch(options[:algorithm]) { + raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") + } + end + + using = "USING #{options[:using]}" if options[:using].present? + + if supports_partial_index? + index_options = options[:where] ? " WHERE #{options[:where]}" : "" + end + + if index_name.length > max_index_length + raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" + end + if table_exists?(table_name) && index_name_exists?(table_name, index_name, false) + raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" + end + index_columns = quoted_columns_for_index(column_names, options).join(", ") + + [index_name, index_type, index_columns, index_options, algorithm, using] + end + protected def add_index_sort_order(option_strings, column_names, options = {}) if options.is_a?(Hash) && order = options[:order] @@ -769,40 +803,6 @@ module ActiveRecord options.include?(:default) && !(options[:null] == false && options[:default].nil?) end - def add_index_options(table_name, column_name, options = {}) - column_names = Array(column_name) - index_name = index_name(table_name, column: column_names) - - options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) - - index_type = options[:unique] ? "UNIQUE" : "" - index_type = options[:type].to_s if options.key?(:type) - index_name = options[:name].to_s if options.key?(:name) - max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length - - if options.key?(:algorithm) - algorithm = index_algorithms.fetch(options[:algorithm]) { - raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") - } - end - - using = "USING #{options[:using]}" if options[:using].present? - - if supports_partial_index? - index_options = options[:where] ? " WHERE #{options[:where]}" : "" - end - - if index_name.length > max_index_length - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" - end - if table_exists?(table_name) && index_name_exists?(table_name, index_name, false) - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" - end - index_columns = quoted_columns_for_index(column_names, options).join(", ") - - [index_name, index_type, index_columns, index_options, algorithm, using] - end - def index_name_for_remove(table_name, options = {}) index_name = index_name(table_name, options) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index c74b916502..b9fd75b610 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -44,7 +44,7 @@ module ActiveRecord end def index_in_create(table_name, column_name, options) - index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.send(:add_index_options, table_name, column_name, options) + index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options) "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}".gsub(' ', ' ').strip end end -- cgit v1.2.3 From 03d4ed3827da2086a8c8dadf4c25666248a39c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:18:59 -0300 Subject: No need to gsub the string --- .../lib/active_record/connection_adapters/abstract_mysql_adapter.rb | 2 +- activerecord/test/cases/adapters/mysql/active_schema_test.rb | 2 +- activerecord/test/cases/adapters/mysql2/active_schema_test.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index b9fd75b610..e4c6502bb7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -45,7 +45,7 @@ module ActiveRecord def index_in_create(table_name, column_name, options) index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options) - "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}".gsub(' ', ' ').strip + "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}" end end diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index 35681fb5ae..b27bd652f2 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -121,7 +121,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase begin ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) - expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| t.index :zip end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 925b9c1bd1..c15ecddd69 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -121,7 +121,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase begin ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) - expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| t.index :zip end -- cgit v1.2.3 From 8a37f3b59cb1399f71f02d9684fd9defcbd97697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:30:28 -0300 Subject: No need to use begin/end blocks --- .../test/cases/adapters/mysql/active_schema_test.rb | 16 ++++++++-------- .../test/cases/adapters/mysql2/active_schema_test.rb | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index b27bd652f2..d1c644c016 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -118,15 +118,15 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_indexes_in_create - begin - ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) - ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) - expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" - actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| - t.index :zip - end - assert_equal expected, actual + ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) + ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) + + expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| + t.index :zip end + + assert_equal expected, actual end private diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index c15ecddd69..81c614924f 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -118,15 +118,15 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_indexes_in_create - begin - ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) - ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) - expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" - actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| - t.index :zip - end - assert_equal expected, actual + ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false) + ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) + + expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query" + actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| + t.index :zip end + + assert_equal expected, actual end private -- cgit v1.2.3 From cbe1bc29722ddeda12d8652c409cea156ddb85a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:31:32 -0300 Subject: Improve CHANGELOG entry --- activerecord/CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index ccd07ce248..42b7618fa7 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,8 +1,10 @@ -* Create indexes inline in CREATE TABLE for MySQL +* Create indexes inline in CREATE TABLE for MySQL. This is important, because adding an index on a temporary table after it has been created would commit the transaction. - It also allows creating and dropping indexed tables with fewer queries and fewer permissions required. + + It also allows creating and dropping indexed tables with fewer queries and fewer permissions + required. Example: @@ -11,7 +13,7 @@ end # => CREATE TEMPORARY TABLE temp (INDEX (zip)) AS SELECT id, name, zip FROM a_really_complicated_query - *Cody Cutrer*, *Steve Rice* + *Cody Cutrer*, *Steve Rice*, *Rafael Mendonça Franca* * Save `has_one` association even if the record doesn't changed. -- cgit v1.2.3 From 054e2c42a532d4f160bdb36d2b3864880c16ce4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 20:34:16 -0300 Subject: Remove unused method This method is not being called anywhere in our code and a GitHub search show it is not being used in any project. --- .../lib/active_record/connection_adapters/abstract_adapter.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 05e9b03e3a..ffd5055dec 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -157,11 +157,6 @@ module ActiveRecord false end - # Does this adapter support using DISTINCT within COUNT? - def supports_count_distinct? - true - end - # Does this adapter support DDL rollbacks in transactions? That is, would # CREATE TABLE or ALTER TABLE get rolled back by a transaction? def supports_ddl_transactions? -- cgit v1.2.3 From 7f62f30f58fe5f2955e3292ab1f01aa2c9a8f0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 22:18:53 -0300 Subject: Edge Rails applications doesn't need to use arel master --- railties/lib/rails/generators/app_base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index dd1438800c..2fb49479fe 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -203,8 +203,7 @@ module Rails [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), GemfileEntry.github('arel', 'rails/arel')] elsif options.edge? - [GemfileEntry.github('rails', 'rails/rails'), - GemfileEntry.github('arel', 'rails/arel')] + [GemfileEntry.github('rails', 'rails/rails')] else [GemfileEntry.version('rails', Rails::VERSION::STRING, -- cgit v1.2.3 From 8a081db3575431380592ce2b8f0045e627a4e664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 26 Mar 2014 22:19:29 -0300 Subject: Fix build with bundler 1.6 --- railties/test/generators/plugin_generator_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 7ebc015fe2..7a2701f813 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -156,7 +156,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/bukkits/, contents) end assert_match(/run bundle install/, result) - assert_match(/Using bukkits \(0\.0\.1\)/, result) + assert_match(/Using bukkits \(?0\.0\.1\)?/, result) assert_match(/Your bundle is complete/, result) assert_equal 1, result.scan("Your bundle is complete").size end -- cgit v1.2.3 From ff8f9f09f487cf1965921da74c4b2bffa15a2bb6 Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Wed, 26 Mar 2014 22:23:42 -0300 Subject: Add a test case for save(validate:false) with invalid foreign key. It is supposed to raise ActiveRecord::InvalidForeignKey when the database has a fk constraint. --- activerecord/test/cases/adapter_test.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 696b859b36..ed4d0d503d 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -146,7 +146,7 @@ module ActiveRecord end def test_foreign_key_violations_are_translated_to_specific_exception - unless @connection.adapter_name == 'SQLite' + unless current_adapter?(:SQLite3Adapter) assert_raises(ActiveRecord::InvalidForeignKey) do # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method if @connection.prefetch_primary_key? @@ -159,6 +159,20 @@ module ActiveRecord end end + def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false + unless current_adapter?(:SQLite3Adapter) + klass_has_fk = Class.new(ActiveRecord::Base) do + self.table_name = 'fk_test_has_fk' + end + + assert_raises(ActiveRecord::InvalidForeignKey) do + has_fk = klass_has_fk.new + has_fk.fk_id = 1231231231 + has_fk.save(validate: false) + end + end + end + def test_disable_referential_integrity assert_nothing_raised do @connection.disable_referential_integrity do -- cgit v1.2.3 From 70a4144622d6a43891f43901fec6c05afbd79a3a Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Thu, 27 Mar 2014 11:24:31 +0100 Subject: only run citext_test if the connection supports_extensions?. This will keep the test suite passing with older PG installations. --- .../test/cases/adapters/postgresql/citext_test.rb | 106 +++++++++++---------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb index 148dc9d07c..0bb2949371 100644 --- a/activerecord/test/cases/adapters/postgresql/citext_test.rb +++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb @@ -4,74 +4,76 @@ require 'cases/helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' -class PostgresqlCitextTest < ActiveRecord::TestCase - class Citext < ActiveRecord::Base - self.table_name = 'citexts' - end +if ActiveRecord::Base.connection.supports_extensions? + class PostgresqlCitextTest < ActiveRecord::TestCase + class Citext < ActiveRecord::Base + self.table_name = 'citexts' + end - def setup - @connection = ActiveRecord::Base.connection + def setup + @connection = ActiveRecord::Base.connection - unless @connection.extension_enabled?('citext') - @connection.enable_extension 'citext' - @connection.commit_db_transaction - end + unless @connection.extension_enabled?('citext') + @connection.enable_extension 'citext' + @connection.commit_db_transaction + end - @connection.reconnect! + @connection.reconnect! - @connection.create_table('citexts') do |t| - t.citext 'cival' + @connection.create_table('citexts') do |t| + t.citext 'cival' + end + @column = Citext.columns_hash['cival'] end - @column = Citext.columns_hash['cival'] - end - teardown do - @connection.execute 'DROP TABLE IF EXISTS citexts;' - @connection.execute 'DROP EXTENSION IF EXISTS citext CASCADE;' - end + teardown do + @connection.execute 'DROP TABLE IF EXISTS citexts;' + @connection.execute 'DROP EXTENSION IF EXISTS citext CASCADE;' + end - def test_citext_enabled - assert @connection.extension_enabled?('citext') - end + def test_citext_enabled + assert @connection.extension_enabled?('citext') + end - def test_column_type - assert_equal :citext, @column.type - end + def test_column_type + assert_equal :citext, @column.type + end - def test_column_sql_type - assert_equal 'citext', @column.sql_type - end + def test_column_sql_type + assert_equal 'citext', @column.sql_type + end + + def test_change_table_supports_json + @connection.transaction do + @connection.change_table('citexts') do |t| + t.citext 'username' + end + Citext.reset_column_information + column = Citext.columns.find { |c| c.name == 'username' } + assert_equal :citext, column.type - def test_change_table_supports_json - @connection.transaction do - @connection.change_table('citexts') do |t| - t.citext 'username' + raise ActiveRecord::Rollback # reset the schema change end + ensure Citext.reset_column_information - column = Citext.columns.find { |c| c.name == 'username' } - assert_equal :citext, column.type - - raise ActiveRecord::Rollback # reset the schema change end - ensure - Citext.reset_column_information - end - def test_write - x = Citext.new(cival: 'Some CI Text') - x.save! - citext = Citext.first - assert_equal "Some CI Text", citext.cival + def test_write + x = Citext.new(cival: 'Some CI Text') + x.save! + citext = Citext.first + assert_equal "Some CI Text", citext.cival - citext.cival = "Some NEW CI Text" - citext.save! + citext.cival = "Some NEW CI Text" + citext.save! - assert_equal "Some NEW CI Text", citext.reload.cival - end + assert_equal "Some NEW CI Text", citext.reload.cival + end - def test_select_case_insensitive - @connection.execute "insert into citexts (cival) values('Cased Text')" - x = Citext.where(cival: 'cased text').first - assert_equal 'Cased Text', x.cival + def test_select_case_insensitive + @connection.execute "insert into citexts (cival) values('Cased Text')" + x = Citext.where(cival: 'cased text').first + assert_equal 'Cased Text', x.cival + end end end -- cgit v1.2.3 From 5bf38ffc4f853a6ccc5812f0ed8341776b117aea Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Thu, 27 Mar 2014 11:55:46 +0100 Subject: require dependency to execute a single test from xml_serialization_test When the tests are executed in order, the dependency is loaded at the right time. However this makes it impossible to execute a single test later down the line. Let's require the dependecy at the beginning to get them working independent of the order. This resolves the following error: ``` $ ARCONN=postgresql ruby -Itest /Users/senny/Projects/rails/activerecord/test/cases/xml_serialization_test.rb -n test_to_xml Using postgresql Run options: -n test_to_xml --seed 51819 E Finished in 0.081320s, 12.2971 runs/s, 0.0000 assertions/s. 1) Error: DatabaseConnectedXmlSerializationTest#test_to_xml: NameError: uninitialized constant DatabaseConnectedXmlSerializationTest::REXML /Users/senny/Projects/rails/activerecord/test/cases/xml_serialization_test.rb:226:in `test_to_xml' ``` /cc @tgxworld fyi --- activerecord/test/cases/xml_serialization_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb index 78fa2f935a..3cb617497d 100644 --- a/activerecord/test/cases/xml_serialization_test.rb +++ b/activerecord/test/cases/xml_serialization_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require "rexml/document" require 'models/contact' require 'models/post' require 'models/author' -- cgit v1.2.3 From 15a18c18e496c8fb46ee21d8a1af0c4012abc5f5 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Thu, 27 Mar 2014 16:37:47 +0530 Subject: Clarify environment_name for logs [ci skip] --- guides/source/debugging_rails_applications.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 226137c89a..99f685e535 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -123,7 +123,7 @@ config.logger = Logger.new(STDOUT) config.logger = Log4r::Logger.new("Application Log") ``` -TIP: By default, each log is created under `Rails.root/log/` and the log file name is `environment_name.log`. +TIP: By default, each log is created under `Rails.root/log/` and the log file name is `environment_name.log`. example `production.log`, `development.log` etc. ### Log Levels -- cgit v1.2.3 From 2e70f44123cb6fab9124b52a6cc02ff453b8397f Mon Sep 17 00:00:00 2001 From: Henrik Nyh Date: Sun, 23 Mar 2014 12:09:55 +0100 Subject: ActiveRecord/ActiveModel '#validate' alias for 'valid?' It's unintuitive to call '#valid?' when you want to run validations but don't care about the return value. The alias in ActiveRecord isn't strictly necessary (the ActiveModel alias is still in effect), but it clarifies. --- activemodel/lib/active_model/validations.rb | 4 ++++ activemodel/test/cases/validations_test.rb | 9 +++++++++ activerecord/CHANGELOG.md | 6 ++++++ activerecord/lib/active_record/validations.rb | 4 ++++ activerecord/test/cases/validations_test.rb | 15 +++++++++++++++ 5 files changed, 38 insertions(+) diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index e9674d5143..cf97f45dba 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -285,6 +285,8 @@ module ActiveModel # Runs all the specified validations and returns +true+ if no errors were # added otherwise +false+. # + # Aliased as validate. + # # class Person # include ActiveModel::Validations # @@ -319,6 +321,8 @@ module ActiveModel self.validation_context = current_context end + alias_method :validate, :valid? + # Performs the opposite of valid?. Returns +true+ if errors were # added, +false+ otherwise. # diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 4ea5670d32..6a74ee353d 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -295,6 +295,15 @@ class ValidationsTest < ActiveModel::TestCase assert auto.valid? end + def test_validate + auto = Automobile.new + + assert_empty auto.errors + + auto.validate + assert_not_empty auto.errors + end + def test_strict_validation_in_validates Topic.validates :title, strict: true, presence: true assert_raises ActiveModel::StrictValidationFailed do diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 42b7618fa7..916d24aa03 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Introduce `validate` as an alias for `valid?`. + + This is more intuitive when you want to run validations but don't care about the return value. + + *Henrik Nyh* + * Create indexes inline in CREATE TABLE for MySQL. This is important, because adding an index on a temporary table after it has been created diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 26dca415ff..9999624fcf 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -60,6 +60,8 @@ module ActiveRecord # Runs all the validations within the specified context. Returns +true+ if # no errors are found, +false+ otherwise. # + # Aliased as validate. + # # If the argument is +false+ (default is +nil+), the context is set to :create if # new_record? is +true+, and to :update if it is not. # @@ -71,6 +73,8 @@ module ActiveRecord errors.empty? && output end + alias_method :validate, :valid? + protected def perform_validations(options={}) # :nodoc: diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index de618902aa..d80da06e27 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -52,6 +52,21 @@ class ValidationsTest < ActiveRecord::TestCase assert r.save(:context => :special_case) end + def test_validate + r = WrongReply.new + + r.validate + assert_empty r.errors[:author_name] + + r.validate(:special_case) + assert_not_empty r.errors[:author_name] + + r.author_name = "secret" + + r.validate(:special_case) + assert_empty r.errors[:author_name] + end + def test_invalid_record_exception assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! } assert_raise(ActiveRecord::RecordInvalid) { WrongReply.new.save! } -- cgit v1.2.3 From eddcdb0f1de6e7b1b503a6df8d60cd6a145ce080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 27 Mar 2014 14:16:57 -0300 Subject: Add CHANGELOG to Active Model too [ci skip] --- activemodel/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index f9246e6c81..0db220ab8f 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1 +1,7 @@ +* Introduce `validate` as an alias for `valid?`. + + This is more intuitive when you want to run validations but don't care about the return value. + + *Henrik Nyh* + Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/activemodel/CHANGELOG.md) for previous changes. -- cgit v1.2.3 From 3a661794382c3b06cbb4d6dcc1859dd569cf8652 Mon Sep 17 00:00:00 2001 From: chrisfinne Date: Sat, 15 Mar 2014 03:32:24 -0700 Subject: AR .persisted? throws SystemStackError for an unsaved model with a custom primary_key that didn't save due to validation error --- activerecord/CHANGELOG.md | 7 +++++++ activerecord/lib/active_record/transactions.rb | 2 +- activerecord/test/cases/transactions_test.rb | 6 ++++++ activerecord/test/models/movie.rb | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 916d24aa03..b08f6ff38b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fixed error where .persisted? throws SystemStackError for an unsaved model with a + custom primary key that didn't save due to validation error. + + Fixes #14393. + + *Chris Finne* + * Introduce `validate` as an alias for `valid?`. This is more intuitive when you want to run validations but don't care about the return value. diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index ec3e8f281b..17f76b63b3 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -369,7 +369,7 @@ module ActiveRecord @new_record = restore_state[:new_record] @destroyed = restore_state[:destroyed] if restore_state.has_key?(:id) - self.id = restore_state[:id] + write_attribute(self.class.primary_key, restore_state[:id]) else @attributes.delete(self.class.primary_key) @attributes_cache.delete(self.class.primary_key) diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 1664f1a096..e6ed85394b 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -5,6 +5,7 @@ require 'models/developer' require 'models/book' require 'models/author' require 'models/post' +require 'models/movie' class TransactionTest < ActiveRecord::TestCase self.use_transactional_fixtures = false @@ -14,6 +15,11 @@ class TransactionTest < ActiveRecord::TestCase @first, @second = Topic.find(1, 2).sort_by { |t| t.id } end + def test_persisted_in_a_model_with_custom_primary_key_after_failed_save + movie = Movie.create + assert !movie.persisted? + end + def test_raise_after_destroy assert_not @first.frozen? diff --git a/activerecord/test/models/movie.rb b/activerecord/test/models/movie.rb index c441be2bef..0302abad1e 100644 --- a/activerecord/test/models/movie.rb +++ b/activerecord/test/models/movie.rb @@ -1,3 +1,5 @@ class Movie < ActiveRecord::Base self.primary_key = "movieid" + + validates_presence_of :name end -- cgit v1.2.3 From d93bfac207c258167257676035c9b0b2912fba5c Mon Sep 17 00:00:00 2001 From: David Underwood Date: Thu, 27 Mar 2014 16:13:56 -0400 Subject: Adds explanation of :base attribute to errors.add [ci skip] --- activemodel/lib/active_model/errors.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 9c3bc913e1..917d3b9142 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -289,6 +289,13 @@ module ActiveModel # # => NameIsInvalid: name is invalid # # person.errors.messages # => {} + # + # +attribute+ should be set to :base if the error is not + # directly associated with a single attribute. + # + # person.errors.add(:base, "either name or email must be present") + # person.errors.messages + # # => {:base=>["either name or email must be present"]} def add(attribute, message = :invalid, options = {}) message = normalize_message(attribute, message, options) if exception = options[:strict] -- cgit v1.2.3 From dd3ea17191e316aeebddaa7b176f6cfeee7a6365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 27 Mar 2014 16:10:17 -0500 Subject: Merge pull request #14469 from tiegz/timestamp_inheritance_fix Swap Timestamp/Callbacks order in ActiveRecord::Base --- activerecord/CHANGELOG.md | 4 ++++ activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/timestamp_test.rb | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b08f6ff38b..fe18ae995c 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Make possible to change `record_timestamps` inside Callbacks. + + *Tieg Zaharia* + * Fixed error where .persisted? throws SystemStackError for an unsaved model with a custom primary key that didn't save due to validation error. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 9ec1feea97..1d47cba234 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -310,8 +310,8 @@ module ActiveRecord #:nodoc: include Locking::Optimistic include Locking::Pessimistic include AttributeMethods - include Callbacks include Timestamp + include Callbacks include Associations include ActiveModel::SecurePassword include AutosaveAssociation diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index 5308fa8808..594b4fb07b 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -71,6 +71,24 @@ class TimestampTest < ActiveRecord::TestCase assert_equal @previously_updated_at, @developer.updated_at end + def test_saving_when_callback_sets_record_timestamps_to_false_doesnt_update_its_timestamp + klass = Class.new(Developer) do + before_update :cancel_record_timestamps + def cancel_record_timestamps + self.record_timestamps = false + return true + end + end + + developer = klass.first + previously_updated_at = developer.updated_at + + developer.name = "New Name" + developer.save! + + assert_equal previously_updated_at, developer.updated_at + end + def test_touching_an_attribute_updates_timestamp previously_created_at = @developer.created_at @developer.touch(:created_at) -- cgit v1.2.3 From 13b618f48d0c31184577c11cf8b89437b4bc1ce6 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Fri, 28 Mar 2014 09:40:21 +0100 Subject: PostgreSQL, test cases to lock the current column types. --- .../test/cases/adapters/postgresql/array_test.rb | 3 +++ .../test/cases/adapters/postgresql/citext_test.rb | 15 ++++++++------- .../test/cases/adapters/postgresql/composite_test.rb | 11 +++++++++++ .../test/cases/adapters/postgresql/enum_test.rb | 11 +++++++++++ .../test/cases/adapters/postgresql/hstore_test.rb | 5 +++++ .../test/cases/adapters/postgresql/json_test.rb | 20 +++++++++++++------- .../test/cases/adapters/postgresql/ltree_test.rb | 10 ++++++++++ .../test/cases/adapters/postgresql/uuid_test.rb | 8 +++++++- 8 files changed, 68 insertions(+), 15 deletions(-) diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index f5f1c791e1..1802ef654f 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -25,8 +25,11 @@ class PostgresqlArrayTest < ActiveRecord::TestCase def test_column assert_equal :string, @column.type + assert_equal "character varying(255)", @column.sql_type assert @column.array assert_not @column.text? + assert_not @column.number? + assert_not @column.binary? ratings_column = PgArray.columns_hash['ratings'] assert_equal :integer, ratings_column.type diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb index 0bb2949371..948bf49a54 100644 --- a/activerecord/test/cases/adapters/postgresql/citext_test.rb +++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb @@ -23,7 +23,6 @@ if ActiveRecord::Base.connection.supports_extensions? @connection.create_table('citexts') do |t| t.citext 'cival' end - @column = Citext.columns_hash['cival'] end teardown do @@ -35,12 +34,14 @@ if ActiveRecord::Base.connection.supports_extensions? assert @connection.extension_enabled?('citext') end - def test_column_type - assert_equal :citext, @column.type - end - - def test_column_sql_type - assert_equal 'citext', @column.sql_type + def test_column + column = Citext.columns_hash['cival'] + assert_equal :citext, column.type + assert_equal 'citext', column.sql_type + assert_not column.text? + assert_not column.number? + assert_not column.binary? + assert_not column.array end def test_change_table_supports_json diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb index ed39204145..224b1b770b 100644 --- a/activerecord/test/cases/adapters/postgresql/composite_test.rb +++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb @@ -29,6 +29,17 @@ class PostgresqlCompositeTest < ActiveRecord::TestCase end end + def test_column + column = PostgresqlComposite.columns_hash["address"] + # TODO: Composite columns should have a type + assert_nil column.type + assert_equal "full_address", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + def test_composite_mapping @connection.execute "INSERT INTO postgresql_composites VALUES (1, ROW('Paris', 'Champs-Élysées'));" composite = PostgresqlComposite.first diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index 7208edef5f..381c397922 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -27,6 +27,17 @@ class PostgresqlEnumTest < ActiveRecord::TestCase @connection.send(:reload_type_map) end + def test_column + column = PostgresqlEnum.columns_hash["current_mood"] + # TODO: enum columns should be of type enum or string, not nil. + assert_nil column.type + assert_equal "mood", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + def test_enum_mapping @connection.execute "INSERT INTO postgresql_enums VALUES (1, 'sad');" enum = PostgresqlEnum.first diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 90ec1524b5..a70dadee56 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -54,6 +54,11 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase def test_column assert_equal :hstore, @column.type + assert_equal "hstore", @column.sql_type + assert_not @column.number? + assert_not @column.text? + assert_not @column.binary? + assert_not @column.array end def test_change_table_supports_hstore diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index 10c0a6c395..1590624b2b 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -31,7 +31,13 @@ class PostgresqlJSONTest < ActiveRecord::TestCase end def test_column - assert_equal :json, @column.type + column = JsonDataType.columns_hash["payload"] + assert_equal :json, column.type + assert_equal "json", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array end def test_change_table_supports_json @@ -57,16 +63,16 @@ class PostgresqlJSONTest < ActiveRecord::TestCase end def test_type_cast_json - assert @column + column = JsonDataType.columns_hash["payload"] data = "{\"a_key\":\"a_value\"}" - hash = @column.class.string_to_json data + hash = column.class.string_to_json data assert_equal({'a_key' => 'a_value'}, hash) - assert_equal({'a_key' => 'a_value'}, @column.type_cast(data)) + assert_equal({'a_key' => 'a_value'}, column.type_cast(data)) - assert_equal({}, @column.type_cast("{}")) - assert_equal({'key'=>nil}, @column.type_cast('{"key": null}')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q({"c":"}", "\"a\"":"b \"a b"}))) + assert_equal({}, column.type_cast("{}")) + assert_equal({'key'=>nil}, column.type_cast('{"key": null}')) + assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast(%q({"c":"}", "\"a\"":"b \"a b"}))) end def test_rewrite diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb index e72fd4360d..718f37a380 100644 --- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -10,6 +10,11 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection + + unless @connection.extension_enabled?('ltree') + @connection.enable_extension 'ltree' + end + @connection.transaction do @connection.create_table('ltrees') do |t| t.ltree 'path' @@ -26,6 +31,11 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase def test_column column = Ltree.columns_hash['path'] assert_equal :ltree, column.type + assert_equal "ltree", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array end def test_write diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index f581c4cf39..f79a7a598b 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -41,7 +41,13 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase end def test_data_type_of_uuid_types - assert_equal :uuid, UUIDType.columns_hash["guid"].type + column = UUIDType.columns_hash["guid"] + assert_equal :uuid, column.type + assert_equal "uuid", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array end def test_uuid_formats -- cgit v1.2.3 From 8753ce1a372a17464bfc118a84fa369a0e4a2285 Mon Sep 17 00:00:00 2001 From: Musannif Zahir Date: Fri, 28 Mar 2014 20:11:58 +0800 Subject: Fix warning for overshadowing XML variable --- activemodel/test/cases/serializers/xml_serialization_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb index 73f316d5e0..5db14c8157 100644 --- a/activemodel/test/cases/serializers/xml_serialization_test.rb +++ b/activemodel/test/cases/serializers/xml_serialization_test.rb @@ -118,10 +118,10 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should include yielded additions" do - xml = @contact.to_xml do |xml| + xml_output = @contact.to_xml do |xml| xml.creator "David" end - assert_match %r{David}, xml + assert_match %r{David}, xml_output end test "should serialize string" do -- cgit v1.2.3 From 03f35a27dc88335550ca0ab1d21e46948c9f5093 Mon Sep 17 00:00:00 2001 From: Peter Jaros Date: Tue, 15 Oct 2013 15:45:07 -0400 Subject: HashWithIndifferentAccess better respects #to_hash In particular, `.new`, `#update`, `#merge`, `#replace` all accept objects which respond to `#to_hash`, even if those objects are not Hashes directly. --- activesupport/CHANGELOG.md | 7 ++++ .../active_support/hash_with_indifferent_access.rb | 7 ++-- activesupport/test/core_ext/hash_ext_test.rb | 40 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 7feb820d4f..556e94d184 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,10 @@ +* `HashWithIndifferentAccess` better respects `#to_hash` on objects it's + given. In particular, `.new`, `#update`, `#merge`, `#replace` all accept + objects which respond to `#to_hash`, even if those objects are not Hashes + directly. + + *Peter Jaros* + * Deprecate `Class#superclass_delegating_accessor`, use `Class#class_attribute` instead. *Akshay Vishnoi* diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 594a4ca938..a4ebdea598 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -55,9 +55,9 @@ module ActiveSupport end def initialize(constructor = {}) - if constructor.is_a?(Hash) + if constructor.respond_to?(:to_hash) super() - update(constructor) + update(constructor.to_hash) else super(constructor) end @@ -72,6 +72,7 @@ module ActiveSupport end def self.new_from_hash_copying_default(hash) + hash = hash.to_hash new(hash).tap do |new_hash| new_hash.default = hash.default end @@ -125,7 +126,7 @@ module ActiveSupport if other_hash.is_a? HashWithIndifferentAccess super(other_hash) else - other_hash.each_pair do |key, value| + other_hash.to_hash.each_pair do |key, value| if block_given? && key?(key) value = yield(convert_key(key), self[key], value) end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 40c8f03374..69a380c7cb 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -23,6 +23,16 @@ class HashExtTest < ActiveSupport::TestCase end end + class HashByConversion + def initialize(hash) + @hash = hash + end + + def to_hash + @hash + end + end + def setup @strings = { 'a' => 1, 'b' => 2 } @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } } @@ -411,6 +421,12 @@ class HashExtTest < ActiveSupport::TestCase assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 } end + def test_update_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + hash.update HashByConversion.new({ :a => 1 }) + assert_equal hash['a'], 1 + end + def test_indifferent_merging hash = HashWithIndifferentAccess.new hash[:a] = 'failure' @@ -430,6 +446,12 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 2, hash['b'] end + def test_merge_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + merged = hash.merge HashByConversion.new({ :a => 1 }) + assert_equal merged['a'], 1 + end + def test_indifferent_replace hash = HashWithIndifferentAccess.new hash[:a] = 42 @@ -442,6 +464,18 @@ class HashExtTest < ActiveSupport::TestCase assert_same hash, replaced end + def test_replace_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + hash[:a] = 42 + + replaced = hash.replace(HashByConversion.new(b: 12)) + + assert hash.key?('b') + assert !hash.key?(:a) + assert_equal 12, hash[:b] + assert_same hash, replaced + end + def test_indifferent_merging_with_block hash = HashWithIndifferentAccess.new hash[:a] = 1 @@ -893,6 +927,12 @@ class HashExtTest < ActiveSupport::TestCase assert_equal({}, h.compact!) assert_equal({}, h) end + + def test_new_with_to_hash_conversion + hash = HashWithIndifferentAccess.new(HashByConversion.new(a: 1)) + assert hash.key?('a') + assert_equal 1, hash[:a] + end end class IWriteMyOwnXML -- cgit v1.2.3 From d8b45832340adacdddf94e251bf6d8787edb1015 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Fri, 28 Mar 2014 16:10:24 +0100 Subject: PostgreSQL, test-cases to lock down column default values. --- activerecord/test/cases/adapters/postgresql/array_test.rb | 11 +++++++++++ activerecord/test/cases/adapters/postgresql/hstore_test.rb | 11 +++++++++++ activerecord/test/cases/adapters/postgresql/json_test.rb | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 1802ef654f..714da83a54 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -37,6 +37,17 @@ class PostgresqlArrayTest < ActiveRecord::TestCase assert_not ratings_column.number? end + def test_default + @connection.add_column 'pg_arrays', 'score', :integer, array: true, default: [4, 4, 2] + PgArray.reset_column_information + column = PgArray.columns_hash["score"] + + assert_equal([4, 4, 2], column.default) + assert_equal([4, 4, 2], PgArray.new.score) + ensure + PgArray.reset_column_information + end + def test_change_column_with_array @connection.add_column :pg_arrays, :snippets, :string, array: true, default: [] @connection.change_column :pg_arrays, :snippets, :text, array: true, default: "{}" diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index a70dadee56..c24c4b0d56 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -61,6 +61,17 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert_not @column.array end + def test_default + @connection.add_column 'hstores', 'permissions', :hstore, default: '"users"=>"read", "articles"=>"write"' + Hstore.reset_column_information + column = Hstore.columns_hash["permissions"] + + assert_equal({"users"=>"read", "articles"=>"write"}, column.default) + assert_equal({"users"=>"read", "articles"=>"write"}, Hstore.new.permissions) + ensure + Hstore.reset_column_information + end + def test_change_table_supports_hstore @connection.transaction do @connection.change_table('hstores') do |t| diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index 1590624b2b..ee793ffff2 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -40,6 +40,17 @@ class PostgresqlJSONTest < ActiveRecord::TestCase assert_not column.array end + def test_default + @connection.add_column 'json_data_type', 'permissions', :json, default: '{"users": "read", "posts": ["read", "write"]}' + JsonDataType.reset_column_information + column = JsonDataType.columns_hash["permissions"] + + assert_equal({"users"=>"read", "posts"=>["read", "write"]}, column.default) + assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.new.permissions) + ensure + JsonDataType.reset_column_information + end + def test_change_table_supports_json @connection.transaction do @connection.change_table('json_data_type') do |t| -- cgit v1.2.3 From a8bd7b16260c217290ef8fe3a166fcceac442c62 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Fri, 28 Mar 2014 16:20:26 +0100 Subject: PostgreSQL, use `PostgreSQLColumn` in PG specific tests. --- .../test/cases/adapters/postgresql/quoting_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 1122f8b9a1..39f5b9b18a 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -10,46 +10,46 @@ module ActiveRecord end def test_type_cast_true - c = Column.new(nil, 1, 'boolean') + c = PostgreSQLColumn.new(nil, 1, OID::Boolean.new, 'boolean') assert_equal 't', @conn.type_cast(true, nil) assert_equal 't', @conn.type_cast(true, c) end def test_type_cast_false - c = Column.new(nil, 1, 'boolean') + c = PostgreSQLColumn.new(nil, 1, OID::Boolean.new, 'boolean') assert_equal 'f', @conn.type_cast(false, nil) assert_equal 'f', @conn.type_cast(false, c) end def test_type_cast_cidr ip = IPAddr.new('255.0.0.0/8') - c = Column.new(nil, ip, 'cidr') + c = PostgreSQLColumn.new(nil, ip, OID::Cidr.new, 'cidr') assert_equal ip, @conn.type_cast(ip, c) end def test_type_cast_inet ip = IPAddr.new('255.1.0.0/8') - c = Column.new(nil, ip, 'inet') + c = PostgreSQLColumn.new(nil, ip, OID::Cidr.new, 'inet') assert_equal ip, @conn.type_cast(ip, c) end def test_quote_float_nan nan = 0.0/0 - c = Column.new(nil, 1, 'float') + c = PostgreSQLColumn.new(nil, 1, OID::Float.new, 'float') assert_equal "'NaN'", @conn.quote(nan, c) end def test_quote_float_infinity infinity = 1.0/0 - c = Column.new(nil, 1, 'float') + c = PostgreSQLColumn.new(nil, 1, OID::Float.new, 'float') assert_equal "'Infinity'", @conn.quote(infinity, c) end def test_quote_cast_numeric fixnum = 666 - c = Column.new(nil, nil, 'varchar') + c = PostgreSQLColumn.new(nil, nil, OID::Decimal.new, 'varchar') assert_equal "'666'", @conn.quote(fixnum, c) - c = Column.new(nil, nil, 'text') + c = PostgreSQLColumn.new(nil, nil, OID::Decimal.new, 'text') assert_equal "'666'", @conn.quote(fixnum, c) end -- cgit v1.2.3 From 555ec36522011862c03b483c53be32410594a51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 28 Mar 2014 12:28:28 -0300 Subject: Add CHANGELOG entry for #12778 [ci skip] --- railties/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 6cf8714177..afbebf5b95 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,7 @@ +* Do not set the Rails environment to test by default when using test_unit Railtie. + + *Konstantin Shabanov* + * Remove sqlite3 lines from `.gitignore` if the application is not using sqlite3. *Dmitrii Golub* -- cgit v1.2.3 From e43cd0a4c9c1d33c7d1007a51ad885a579c0bfbc Mon Sep 17 00:00:00 2001 From: Kelley Reynolds Date: Fri, 28 Mar 2014 13:19:47 -0400 Subject: Replace trivial regexp with string or index, twice as fast --- actionpack/lib/action_controller/metal/http_authentication.rb | 2 +- actionpack/lib/action_dispatch/http/mime_type.rb | 2 +- .../active_record/connection_adapters/abstract/database_statements.rb | 2 +- activerecord/lib/active_record/railties/databases.rake | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 1acc19d74b..2eb7853aa6 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -96,7 +96,7 @@ module ActionController end def user_name_and_password(request) - decode_credentials(request).split(/:/, 2) + decode_credentials(request).split(':', 2) end def decode_credentials(request) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 3d2dd2d632..9450be838c 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -174,7 +174,7 @@ module Mime end def parse(accept_header) - if accept_header !~ /,/ + if !accept_header.include?(',') accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact else diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index e0516c0773..da25e640c1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -318,7 +318,7 @@ module ActiveRecord def sanitize_limit(limit) if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral) limit - elsif limit.to_s =~ /,/ + elsif limit.to_s.include?(',') Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',') else Integer(limit) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index ff1f0f5911..6b0459ea37 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -186,7 +186,7 @@ db_namespace = namespace :db do fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file| + (ENV['FIXTURES'] ? ENV['FIXTURES'].split(',') : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file| ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_file) end end -- cgit v1.2.3 From 0212a41700a4e9cd0a6eb2a0811608ea13f8c5b3 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 28 Mar 2014 18:54:35 -0700 Subject: Fix tests not unsubscribing from Notifications. See https://github.com/rails/rails/blob/master/activesupport/lib/active_support/notifications.rb#L131 --- activerecord/test/cases/adapters/mysql2/connection_test.rb | 4 ++-- activerecord/test/cases/adapters/postgresql/connection_test.rb | 4 ++-- activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb | 4 ++-- activerecord/test/cases/bind_parameter_test.rb | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index 98febd2d75..57d8b8dd99 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -4,12 +4,12 @@ class MysqlConnectionTest < ActiveRecord::TestCase def setup super @subscriber = SQLSubscriber.new - ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) @connection = ActiveRecord::Base.connection end def teardown - ActiveSupport::Notifications.unsubscribe(@subscriber) + ActiveSupport::Notifications.unsubscribe(@subscription) super end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index aa4996133f..514ae20e3c 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -8,12 +8,12 @@ module ActiveRecord def setup super @subscriber = SQLSubscriber.new - ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) @connection = ActiveRecord::Base.connection end def teardown - ActiveSupport::Notifications.unsubscribe(@subscriber) + ActiveSupport::Notifications.unsubscribe(@subscription) super end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 73cb739b2b..78c6e27ff3 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -23,7 +23,7 @@ module ActiveRecord eosql @subscriber = SQLSubscriber.new - ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) end def test_bad_connection @@ -70,7 +70,7 @@ module ActiveRecord end def teardown - ActiveSupport::Notifications.unsubscribe(@subscriber) + ActiveSupport::Notifications.unsubscribe(@subscription) super end diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb index 24eb91bef9..d4b368fe45 100644 --- a/activerecord/test/cases/bind_parameter_test.rb +++ b/activerecord/test/cases/bind_parameter_test.rb @@ -22,11 +22,11 @@ module ActiveRecord @connection = ActiveRecord::Base.connection @listener = LogListener.new @pk = Topic.columns.find { |c| c.primary } - ActiveSupport::Notifications.subscribe('sql.active_record', @listener) + @subscriber = ActiveSupport::Notifications.subscribe('sql.active_record', @listener) end teardown do - ActiveSupport::Notifications.unsubscribe(@listener) + ActiveSupport::Notifications.unsubscribe(@subscriber) end if ActiveRecord::Base.connection.supports_statement_cache? -- cgit v1.2.3 From 945dd254ae4a79705c2c05a683fc37a8c98c8aeb Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sat, 29 Mar 2014 04:27:23 -0700 Subject: Ensure we are returning either `true` or `false` for `#==` 460eb83d cused `ActiveRecord::Base#==` to sometimes return `nil` in some cases, this ensures we always return a boolean value. Also fixed a similar problem in AR reflections. --- activerecord/lib/active_record/core.rb | 2 +- activerecord/lib/active_record/reflection.rb | 2 +- activerecord/test/cases/base_test.rb | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index d9aaf8597f..4e53f66005 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -299,7 +299,7 @@ module ActiveRecord def ==(comparison_object) super || comparison_object.instance_of?(self.class) && - id && + !id.nil? && comparison_object.id == id end alias :eql? :== diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index bce7766501..03b5bdc46c 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -151,7 +151,7 @@ module ActiveRecord super || other_aggregation.kind_of?(self.class) && name == other_aggregation.name && - other_aggregation.options && + !other_aggregation.options.nil? && active_record == other_aggregation.active_record end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 6acb342d0b..4969344763 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -533,6 +533,7 @@ class BasicsTest < ActiveRecord::TestCase def test_equality_of_new_records assert_not_equal Topic.new, Topic.new + assert_equal false, Topic.new == Topic.new end def test_equality_of_destroyed_records @@ -544,6 +545,12 @@ class BasicsTest < ActiveRecord::TestCase assert_equal topic_2, topic_1 end + def test_equality_with_blank_ids + one = Subscriber.new(:id => '') + two = Subscriber.new(:id => '') + assert_equal one, two + end + def test_hashing assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ] end @@ -578,12 +585,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal nil, Topic.find_by_id(topic.id) end - def test_blank_ids - one = Subscriber.new(:id => '') - two = Subscriber.new(:id => '') - assert_equal one, two - end - def test_comparison_with_different_objects topic = Topic.create category = Category.create(:name => "comparison") -- cgit v1.2.3 From f8872d658e7f2bee3a18be47c01754368f22ab73 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 29 Mar 2014 17:08:07 +0530 Subject: copy edit [ci skip] --- guides/source/debugging_rails_applications.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 99f685e535..0e10d1b697 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -123,7 +123,7 @@ config.logger = Logger.new(STDOUT) config.logger = Log4r::Logger.new("Application Log") ``` -TIP: By default, each log is created under `Rails.root/log/` and the log file name is `environment_name.log`. example `production.log`, `development.log` etc. +TIP: By default, each log is created under `Rails.root/log/` and the log file is named after the environment in which the application is running. ### Log Levels -- cgit v1.2.3 From 0264762fea55f51c92b477ae7d65fa87179f095d Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Mon, 24 Mar 2014 20:38:10 -0700 Subject: Refactor test to use DdlHelper. Follow-Up to https://github.com/rails/rails/pull/14400 This ensures that all tables are removed after each test and thereby allowing us to run the tests in a random order. --- .../cases/adapters/sqlite3/sqlite3_adapter_test.rb | 363 +++++++++++---------- activerecord/test/cases/helper.rb | 2 +- 2 files changed, 198 insertions(+), 167 deletions(-) diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 78c6e27ff3..c2a255451e 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -2,28 +2,22 @@ require "cases/helper" require 'models/owner' require 'tempfile' +require 'support/ddl_helper' module ActiveRecord module ConnectionAdapters class SQLite3AdapterTest < ActiveRecord::TestCase + include DdlHelper + self.use_transactional_fixtures = false class DualEncoding < ActiveRecord::Base end def setup - @conn = Base.sqlite3_connection :database => ':memory:', - :adapter => 'sqlite3', - :timeout => 100 - @conn.execute <<-eosql - CREATE TABLE items ( - id integer PRIMARY KEY AUTOINCREMENT, - number integer - ) - eosql - - @subscriber = SQLSubscriber.new - @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @conn = Base.sqlite3_connection database: ':memory:', + adapter: 'sqlite3', + timeout: 100 end def test_bad_connection @@ -57,8 +51,10 @@ module ActiveRecord end def test_valid_column - column = @conn.columns('items').find { |col| col.name == 'id' } - assert @conn.valid_type?(column.type) + with_example_table do + column = @conn.columns('ex').find { |col| col.name == 'id' } + assert @conn.valid_type?(column.type) + end end # sqlite databases should be able to support any type and not @@ -69,13 +65,8 @@ module ActiveRecord assert @conn.valid_type?(:foobar) end - def teardown - ActiveSupport::Notifications.unsubscribe(@subscription) - super - end - def test_column_types - owner = Owner.create!(:name => "hello".encode('ascii-8bit')) + owner = Owner.create!(name: "hello".encode('ascii-8bit')) owner.reload select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ', ' result = Owner.connection.exec_query <<-esql @@ -85,23 +76,28 @@ module ActiveRecord esql assert(!result.rows.first.include?("blob"), "should not store blobs") + ensure + owner.delete end def test_exec_insert - column = @conn.columns('items').find { |col| col.name == 'number' } - vals = [[column, 10]] - @conn.exec_insert('insert into items (number) VALUES (?)', 'SQL', vals) + with_example_table do + column = @conn.columns('ex').find { |col| col.name == 'number' } + vals = [[column, 10]] + @conn.exec_insert('insert into ex (number) VALUES (?)', 'SQL', vals) - result = @conn.exec_query( - 'select number from items where number = ?', 'SQL', vals) + result = @conn.exec_query( + 'select number from ex where number = ?', 'SQL', vals) - assert_equal 1, result.rows.length - assert_equal 10, result.rows.first.first + assert_equal 1, result.rows.length + assert_equal 10, result.rows.first.first + end end def test_primary_key_returns_nil_for_no_pk - @conn.exec_query('create table ex(id int, data string)') - assert_nil @conn.primary_key('ex') + with_example_table 'id int, data string' do + assert_nil @conn.primary_key('ex') + end end def test_connection_no_db @@ -112,17 +108,17 @@ module ActiveRecord def test_bad_timeout assert_raises(TypeError) do - Base.sqlite3_connection :database => ':memory:', - :adapter => 'sqlite3', - :timeout => 'usa' + Base.sqlite3_connection database: ':memory:', + adapter: 'sqlite3', + timeout: 'usa' end end # connection is OK with a nil timeout def test_nil_timeout - conn = Base.sqlite3_connection :database => ':memory:', - :adapter => 'sqlite3', - :timeout => nil + conn = Base.sqlite3_connection database: ':memory:', + adapter: 'sqlite3', + timeout: nil assert conn, 'made a connection' end @@ -141,44 +137,47 @@ module ActiveRecord end def test_exec_no_binds - @conn.exec_query('create table ex(id int, data string)') - result = @conn.exec_query('SELECT id, data FROM ex') - assert_equal 0, result.rows.length - assert_equal 2, result.columns.length - assert_equal %w{ id data }, result.columns - - @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec_query('SELECT id, data FROM ex') - assert_equal 1, result.rows.length - assert_equal 2, result.columns.length - - assert_equal [[1, 'foo']], result.rows + with_example_table 'id int, data string' do + result = @conn.exec_query('SELECT id, data FROM ex') + assert_equal 0, result.rows.length + assert_equal 2, result.columns.length + assert_equal %w{ id data }, result.columns + + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query('SELECT id, data FROM ex') + assert_equal 1, result.rows.length + assert_equal 2, result.columns.length + + assert_equal [[1, 'foo']], result.rows + end end def test_exec_query_with_binds - @conn.exec_query('create table ex(id int, data string)') - @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec_query( - 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) + with_example_table 'id int, data string' do + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query( + 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) - assert_equal 1, result.rows.length - assert_equal 2, result.columns.length + assert_equal 1, result.rows.length + assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, 'foo']], result.rows + end end def test_exec_query_typecasts_bind_vals - @conn.exec_query('create table ex(id int, data string)') - @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') - column = @conn.columns('ex').find { |col| col.name == 'id' } + with_example_table 'id int, data string' do + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + column = @conn.columns('ex').find { |col| col.name == 'id' } - result = @conn.exec_query( - 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) + result = @conn.exec_query( + 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) - assert_equal 1, result.rows.length - assert_equal 2, result.columns.length + assert_equal 1, result.rows.length + assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, 'foo']], result.rows + end end def test_quote_binary_column_escapes_it @@ -190,7 +189,7 @@ module ActiveRecord ) eosql str = "\x80".force_encoding("ASCII-8BIT") - binary = DualEncoding.new :name => 'いただきます!', :data => str + binary = DualEncoding.new name: 'いただきます!', data: str binary.save! assert_equal str, binary.data @@ -202,16 +201,20 @@ module ActiveRecord name = 'hello'.force_encoding(Encoding::ASCII_8BIT) Owner.create(name: name) assert_equal Encoding::ASCII_8BIT, name.encoding + ensure + Owner.delete_all end def test_execute - @conn.execute "INSERT INTO items (number) VALUES (10)" - records = @conn.execute "SELECT * FROM items" - assert_equal 1, records.length - - record = records.first - assert_equal 10, record['number'] - assert_equal 1, record['id'] + with_example_table do + @conn.execute "INSERT INTO ex (number) VALUES (10)" + records = @conn.execute "SELECT * FROM ex" + assert_equal 1, records.length + + record = records.first + assert_equal 10, record['number'] + assert_equal 1, record['id'] + end end def test_quote_string @@ -219,128 +222,141 @@ module ActiveRecord end def test_insert_sql - 2.times do |i| - rv = @conn.insert_sql "INSERT INTO items (number) VALUES (#{i})" - assert_equal(i + 1, rv) + with_example_table do + 2.times do |i| + rv = @conn.insert_sql "INSERT INTO ex (number) VALUES (#{i})" + assert_equal(i + 1, rv) + end + + records = @conn.execute "SELECT * FROM ex" + assert_equal 2, records.length end - - records = @conn.execute "SELECT * FROM items" - assert_equal 2, records.length end def test_insert_sql_logged - sql = "INSERT INTO items (number) VALUES (10)" - name = "foo" - - assert_logged([[sql, name, []]]) do - @conn.insert_sql sql, name + with_example_table do + sql = "INSERT INTO ex (number) VALUES (10)" + name = "foo" + assert_logged [[sql, name, []]] do + @conn.insert_sql sql, name + end end end def test_insert_id_value_returned - sql = "INSERT INTO items (number) VALUES (10)" - idval = 'vuvuzela' - id = @conn.insert_sql sql, nil, nil, idval - assert_equal idval, id + with_example_table do + sql = "INSERT INTO ex (number) VALUES (10)" + idval = 'vuvuzela' + id = @conn.insert_sql sql, nil, nil, idval + assert_equal idval, id + end end def test_select_rows - 2.times do |i| - @conn.create "INSERT INTO items (number) VALUES (#{i})" + with_example_table do + 2.times do |i| + @conn.create "INSERT INTO ex (number) VALUES (#{i})" + end + rows = @conn.select_rows 'select number, id from ex' + assert_equal [[0, 1], [1, 2]], rows end - rows = @conn.select_rows 'select number, id from items' - assert_equal [[0, 1], [1, 2]], rows end def test_select_rows_logged - sql = "select * from items" - name = "foo" - - assert_logged([[sql, name, []]]) do - @conn.select_rows sql, name + with_example_table do + sql = "select * from ex" + name = "foo" + assert_logged [[sql, name, []]] do + @conn.select_rows sql, name + end end end def test_transaction - count_sql = 'select count(*) from items' + with_example_table do + count_sql = 'select count(*) from ex' - @conn.begin_db_transaction - @conn.create "INSERT INTO items (number) VALUES (10)" + @conn.begin_db_transaction + @conn.create "INSERT INTO ex (number) VALUES (10)" - assert_equal 1, @conn.select_rows(count_sql).first.first - @conn.rollback_db_transaction - assert_equal 0, @conn.select_rows(count_sql).first.first + assert_equal 1, @conn.select_rows(count_sql).first.first + @conn.rollback_db_transaction + assert_equal 0, @conn.select_rows(count_sql).first.first + end end def test_tables - assert_equal %w{ items }, @conn.tables - - @conn.execute <<-eosql - CREATE TABLE people ( - id integer PRIMARY KEY AUTOINCREMENT, - number integer - ) - eosql - assert_equal %w{ items people }.sort, @conn.tables.sort + with_example_table do + assert_equal %w{ ex }, @conn.tables + with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer', 'people' do + assert_equal %w{ ex people }.sort, @conn.tables.sort + end + end end def test_tables_logs_name - assert_logged [['SCHEMA', []]] do + sql = <<-SQL + SELECT name FROM sqlite_master + WHERE type = 'table' AND NOT name = 'sqlite_sequence' + SQL + assert_logged [[sql.squish, 'SCHEMA', []]] do @conn.tables('hello') - assert_not_nil @subscriber.logged.first.shift end end def test_indexes_logs_name - assert_logged [["PRAGMA index_list(\"items\")", 'SCHEMA', []]] do - @conn.indexes('items', 'hello') + with_example_table do + assert_logged [["PRAGMA index_list(\"ex\")", 'SCHEMA', []]] do + @conn.indexes('ex', 'hello') + end end end def test_table_exists_logs_name - assert @conn.table_exists?('items') - assert_equal 'SCHEMA', @subscriber.logged[0][1] + with_example_table do + sql = <<-SQL + SELECT name FROM sqlite_master + WHERE type = 'table' + AND NOT name = 'sqlite_sequence' AND name = \"ex\" + SQL + assert_logged [[sql.squish, 'SCHEMA', []]] do + assert @conn.table_exists?('ex') + end + end end def test_columns - columns = @conn.columns('items').sort_by { |x| x.name } - assert_equal 2, columns.length - assert_equal %w{ id number }.sort, columns.map { |x| x.name } - assert_equal [nil, nil], columns.map { |x| x.default } - assert_equal [true, true], columns.map { |x| x.null } + with_example_table do + columns = @conn.columns('ex').sort_by { |x| x.name } + assert_equal 2, columns.length + assert_equal %w{ id number }.sort, columns.map { |x| x.name } + assert_equal [nil, nil], columns.map { |x| x.default } + assert_equal [true, true], columns.map { |x| x.null } + end end def test_columns_with_default - @conn.execute <<-eosql - CREATE TABLE columns_with_default ( - id integer PRIMARY KEY AUTOINCREMENT, - number integer default 10 - ) - eosql - column = @conn.columns('columns_with_default').find { |x| - x.name == 'number' - } - assert_equal 10, column.default + with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer default 10' do + column = @conn.columns('ex').find { |x| + x.name == 'number' + } + assert_equal 10, column.default + end end def test_columns_with_not_null - @conn.execute <<-eosql - CREATE TABLE columns_with_default ( - id integer PRIMARY KEY AUTOINCREMENT, - number integer not null - ) - eosql - column = @conn.columns('columns_with_default').find { |x| - x.name == 'number' - } - assert !column.null, "column should not be null" + with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer not null' do + column = @conn.columns('ex').find { |x| x.name == 'number' } + assert_not column.null, "column should not be null" + end end def test_indexes_logs - assert_difference('@subscriber.logged.length') do - @conn.indexes('items') + with_example_table do + assert_logged [["PRAGMA index_list(\"ex\")", "SCHEMA", []]] do + @conn.indexes('ex') + end end - assert_match(/items/, @subscriber.logged.last.first) end def test_no_indexes @@ -348,41 +364,45 @@ module ActiveRecord end def test_index - @conn.add_index 'items', 'id', :unique => true, :name => 'fun' - index = @conn.indexes('items').find { |idx| idx.name == 'fun' } + with_example_table do + @conn.add_index 'ex', 'id', unique: true, name: 'fun' + index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } - assert_equal 'items', index.table - assert index.unique, 'index is unique' - assert_equal ['id'], index.columns + assert_equal 'ex', index.table + assert index.unique, 'index is unique' + assert_equal ['id'], index.columns + end end def test_non_unique_index - @conn.add_index 'items', 'id', :name => 'fun' - index = @conn.indexes('items').find { |idx| idx.name == 'fun' } - assert !index.unique, 'index is not unique' + with_example_table do + @conn.add_index 'ex', 'id', name: 'fun' + index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } + assert_not index.unique, 'index is not unique' + end end def test_compound_index - @conn.add_index 'items', %w{ id number }, :name => 'fun' - index = @conn.indexes('items').find { |idx| idx.name == 'fun' } - assert_equal %w{ id number }.sort, index.columns.sort + with_example_table do + @conn.add_index 'ex', %w{ id number }, name: 'fun' + index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } + assert_equal %w{ id number }.sort, index.columns.sort + end end def test_primary_key - assert_equal 'id', @conn.primary_key('items') - - @conn.execute <<-eosql - CREATE TABLE foos ( - internet integer PRIMARY KEY AUTOINCREMENT, - number integer not null - ) - eosql - assert_equal 'internet', @conn.primary_key('foos') + with_example_table do + assert_equal 'id', @conn.primary_key('ex') + with_example_table 'internet integer PRIMARY KEY AUTOINCREMENT, number integer not null', 'foos' do + assert_equal 'internet', @conn.primary_key('foos') + end + end end def test_no_primary_key - @conn.execute 'CREATE TABLE failboat (number integer not null)' - assert_nil @conn.primary_key('failboat') + with_example_table 'number integer not null' do + assert_nil @conn.primary_key('ex') + end end def test_supports_extensions @@ -400,10 +420,21 @@ module ActiveRecord private def assert_logged logs + subscriber = SQLSubscriber.new + subscription = ActiveSupport::Notifications.subscribe('sql.active_record', subscriber) yield - assert_equal logs, @subscriber.logged + assert_equal logs, subscriber.logged + ensure + ActiveSupport::Notifications.unsubscribe(subscription) end + def with_example_table(definition = nil, table_name = 'ex', &block) + definition ||= <<-SQL + id integer PRIMARY KEY AUTOINCREMENT, + number integer + SQL + super(@conn, table_name, definition, &block) + end end end end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 8a49dfbb44..5ed508a799 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -168,7 +168,7 @@ class SQLSubscriber def start(name, id, payload) @payloads << payload - @logged << [payload[:sql], payload[:name], payload[:binds]] + @logged << [payload[:sql].squish, payload[:name], payload[:binds]] end def finish(name, id, payload); end -- cgit v1.2.3 From 7afe193887ca08625e6952a3cc8c8bb6d6729cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Planas?= Date: Sat, 29 Mar 2014 21:21:01 +0100 Subject: Require yaml explicitly --- railties/lib/rails/application/configuration.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 9aec2f9734..4c449d2c57 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -95,6 +95,7 @@ module Rails yaml = Pathname.new(paths["config/database"].first || "") config = if yaml.exist? + require "yaml" require "erb" YAML.load(ERB.new(yaml.read).result) || {} elsif ENV['DATABASE_URL'] -- cgit v1.2.3 From 74a821760cc5c78d9932bbb1f15ba9cfba89b28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sun, 30 Mar 2014 13:02:04 -0300 Subject: No need to call to_sym It is already called inside type_to_sql method. --- .../lib/active_record/connection_adapters/abstract/schema_creation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index a51691bfa8..8ac20441da 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -13,7 +13,7 @@ module ActiveRecord end def visit_AddColumn(o) - sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale) sql = "ADD #{quote_column_name(o.name)} #{sql_type}" add_column_options!(sql, column_options(o)) end @@ -26,7 +26,7 @@ module ActiveRecord end def visit_ColumnDefinition(o) - sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale) column_sql = "#{quote_column_name(o.name)} #{sql_type}" add_column_options!(column_sql, column_options(o)) unless o.primary_key? column_sql -- cgit v1.2.3 From 78e4862f6f7079c10af44c269bf98046a41bc8cf Mon Sep 17 00:00:00 2001 From: Luke Steensen Date: Sun, 30 Mar 2014 11:10:41 -0500 Subject: fix bug on non empty defaults for pg array columns fixes #10613 --- activerecord/CHANGELOG.md | 6 ++++++ .../connection_adapters/abstract/schema_creation.rb | 8 +++++++- .../connection_adapters/abstract/schema_definitions.rb | 2 +- activerecord/test/cases/adapters/postgresql/array_test.rb | 11 +++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fe18ae995c..18ec203fa3 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Fixed error when specifying a non-empty default value on a PostgreSQL array column. + + Fixes #10613. + + *Luke Steensen* + * Make possible to change `record_timestamps` inside Callbacks. *Tieg Zaharia* diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 8ac20441da..47fe501752 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -64,7 +64,7 @@ module ActiveRecord end def add_column_options!(sql, options) - sql << " DEFAULT #{@conn.quote(options[:default], options[:column])}" if options_include_default?(options) + sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options) # must explicitly check for :null to allow change_column to work on migrations if options[:null] == false sql << " NOT NULL" @@ -75,6 +75,12 @@ module ActiveRecord sql end + def quote_value(value, column) + column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale) + + @conn.quote(value, column) + end + def options_include_default?(options) options.include?(:default) && !(options[:null] == false && options[:default].nil?) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index c39bf15e83..71c3a4378b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -15,7 +15,7 @@ module ActiveRecord # are typically created by methods in TableDefinition, and added to the # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. - class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc: + class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc: def primary_key? primary_key || type.to_sym == :primary_key diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 714da83a54..36ded66998 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -48,6 +48,17 @@ class PostgresqlArrayTest < ActiveRecord::TestCase PgArray.reset_column_information end + def test_default_strings + @connection.add_column 'pg_arrays', 'names', :string, array: true, default: ["foo", "bar"] + PgArray.reset_column_information + column = PgArray.columns_hash["names"] + + assert_equal(["foo", "bar"], column.default) + assert_equal(["foo", "bar"], PgArray.new.names) + ensure + PgArray.reset_column_information + end + def test_change_column_with_array @connection.add_column :pg_arrays, :snippets, :string, array: true, default: [] @connection.change_column :pg_arrays, :snippets, :text, array: true, default: "{}" -- cgit v1.2.3 From 5098bca97d22fd5318eac012ecfbbd5c34c3231d Mon Sep 17 00:00:00 2001 From: Luke Steensen Date: Sun, 30 Mar 2014 12:34:01 -0500 Subject: fix mysql builds --- .../lib/active_record/connection_adapters/abstract_mysql_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index e4c6502bb7..20eea208ec 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -30,7 +30,7 @@ module ActiveRecord options = o.options sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale]) change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}" - add_column_options!(change_column_sql, options) + add_column_options!(change_column_sql, options.merge(column: column)) add_column_position!(change_column_sql, options) end -- cgit v1.2.3 From be521ef6acaf13be027065e24b83461043fb0237 Mon Sep 17 00:00:00 2001 From: Laura Paredes Date: Sun, 30 Mar 2014 20:23:46 +0200 Subject: Do not overwrite selected and disabled attributes --- actionview/lib/action_view/helpers/form_options_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index f625a9ff49..48f42947db 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -360,8 +360,8 @@ module ActionView html_attributes = option_html_attributes(element) text, value = option_text_and_value(element).map { |item| item.to_s } - html_attributes[:selected] = option_value_selected?(value, selected) - html_attributes[:disabled] = disabled && option_value_selected?(value, disabled) + html_attributes[:selected] ||= option_value_selected?(value, selected) + html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled) html_attributes[:value] = value content_tag_string(:option, text, html_attributes) -- cgit v1.2.3 From de32d972bfde8871f7c1a4621f2223ea9b6715b2 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 30 Mar 2014 20:23:50 +0200 Subject: Fix polymorphic preloads on NOT NULL _type columns. Defer to Association#klass instead of having a custom/duplicate code. --- activerecord/lib/active_record/associations/preloader.rb | 11 +---------- activerecord/test/cases/associations/eager_test.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index 83637a0409..e6485b2b0c 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -144,7 +144,7 @@ module ActiveRecord reflection_records.each_with_object({}) do |(reflection, r_records),h| h[reflection] = r_records.group_by { |record| - association_klass(reflection, record) + record.association(association).klass } end end @@ -163,15 +163,6 @@ module ActiveRecord "perhaps you misspelled it?" end - def association_klass(reflection, record) - if reflection.macro == :belongs_to && reflection.options[:polymorphic] - klass = record.read_attribute(reflection.foreign_type.to_s) - klass && klass.constantize - else - reflection.klass - end - end - class AlreadyLoaded attr_reader :owners, :reflection diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index e59161fc5b..d594697280 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -235,6 +235,17 @@ class EagerAssociationTest < ActiveRecord::TestCase end end + def test_finding_with_includes_on_empty_polymorphic_type_column + sponsor = sponsors(:moustache_club_sponsor_for_groucho) + sponsor.update!(sponsorable_type: '', sponsorable_id: nil) # sponsorable_type column might be declared NOT NULL + sponsor = assert_queries(1) do + assert_nothing_raised { Sponsor.all.merge!(:includes => :sponsorable).find(sponsor.id) } + end + assert_no_queries do + assert_equal nil, sponsor.sponsorable + end + end + def test_loading_from_an_association posts = authors(:david).posts.merge(:includes => :comments, :order => "posts.id").to_a assert_equal 2, posts.first.comments.size -- cgit v1.2.3 From 055942d6c526de3a037e76e14954229888668515 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 30 Mar 2014 20:52:01 +0200 Subject: Simplify Preloader#grouped_records code. The new method relies on AR::Associations::Association knowing about both reflection and a model class. AR::Base#association now raises a descriptive error when trying to access non-existent associations. Previously it would blow up with a confusing NoMethodError: undefined method `association_class' for nil:NilClass. --- activerecord/lib/active_record/associations.rb | 8 ++++++- .../lib/active_record/associations/preloader.rb | 26 +++++----------------- activerecord/test/cases/associations/eager_test.rb | 8 +++---- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 860e76fa18..4abe2ad0a0 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -4,6 +4,12 @@ require 'active_support/core_ext/module/remove_method' require 'active_record/errors' module ActiveRecord + class AssociationNotFoundError < ConfigurationError #:nodoc: + def initialize(record, association_name) + super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?") + end + end + class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc: def initialize(reflection, associated_class = nil) super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})") @@ -145,7 +151,7 @@ module ActiveRecord association = association_instance_get(name) if association.nil? - reflection = self.class.reflect_on_association(name) + raise AssociationNotFoundError.new(self, name) unless reflection = self.class.reflect_on_association(name) association = reflection.association_class.new(self, reflection) association_instance_set(name, association) end diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index e6485b2b0c..31ddf4e0fc 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -140,27 +140,13 @@ module ActiveRecord end def grouped_records(association, records) - reflection_records = records_by_reflection(association, records) - - reflection_records.each_with_object({}) do |(reflection, r_records),h| - h[reflection] = r_records.group_by { |record| - record.association(association).klass - } - end - end - - def records_by_reflection(association, records) - records.group_by do |record| - reflection = record.class.reflect_on_association(association) - - reflection || raise_config_error(record, association) + h = {} + records.each do |record| + assoc = record.association(association) + klasses = h[assoc.reflection] ||= {} + (klasses[assoc.klass] ||= []) << record end - end - - def raise_config_error(record, association) - raise ActiveRecord::ConfigurationError, - "Association named '#{association}' was not found on #{record.class.name}; " \ - "perhaps you misspelled it?" + h end class AlreadyLoaded diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index d594697280..8c9797861c 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -720,16 +720,16 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_invalid_association_reference - assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { Post.all.merge!(:includes=> :monkeys ).find(6) } - assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { Post.all.merge!(:includes=>[ :monkeys ]).find(6) } - assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { Post.all.merge!(:includes=>[ 'monkeys' ]).find(6) } - assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { + assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { Post.all.merge!(:includes=>[ :monkeys, :elephants ]).find(6) } end -- cgit v1.2.3 From aa7382a2ea4c0e80de3789f22fd4ebbdf9007051 Mon Sep 17 00:00:00 2001 From: "Ian C. Anderson" Date: Sun, 30 Mar 2014 22:19:30 -0400 Subject: Tiny doc fix for Strong Parameters - accepts_nested_attribute_for -> accepts_nested_attributes_for --- actionpack/lib/action_controller/metal/strong_parameters.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index aff083b502..d86d49c9dc 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -502,7 +502,7 @@ module ActionController # end # end # - # In order to use accepts_nested_attribute_for with Strong \Parameters, you + # In order to use accepts_nested_attributes_for with Strong \Parameters, you # will need to specify which nested attributes should be whitelisted. # # class Person -- cgit v1.2.3 From 5eb13fcaac5c7328e048bf4e5d2d8418fefc5ac1 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Mon, 31 Mar 2014 10:05:24 +0200 Subject: refactor, put `PostgreSQLColumn` into `column.rb`. We have `connection_adapters/column.rb` so it's easier to remember that the column in in a separate file. --- .../connection_adapters/postgresql/column.rb | 221 +++++++++++++++++++++ .../connection_adapters/postgresql_adapter.rb | 219 +------------------- 2 files changed, 222 insertions(+), 218 deletions(-) create mode 100644 activerecord/lib/active_record/connection_adapters/postgresql/column.rb diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb new file mode 100644 index 0000000000..823189934d --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -0,0 +1,221 @@ +module ActiveRecord + module ConnectionAdapters + # PostgreSQL-specific extensions to column definitions in a table. + class PostgreSQLColumn < Column #:nodoc: + attr_accessor :array + + def initialize(name, default, oid_type, sql_type = nil, null = true) + @oid_type = oid_type + default_value = self.class.extract_value_from_default(default) + + if sql_type =~ /\[\]$/ + @array = true + super(name, default_value, sql_type[0..sql_type.length - 3], null) + else + @array = false + super(name, default_value, sql_type, null) + end + + @default_function = default if has_default_function?(default_value, default) + end + + def number? + !array && super + end + + def text? + !array && super + end + + # :stopdoc: + class << self + include ConnectionAdapters::PostgreSQLColumn::Cast + include ConnectionAdapters::PostgreSQLColumn::ArrayParser + attr_accessor :money_precision + end + # :startdoc: + + # Extracts the value from a PostgreSQL column default definition. + def self.extract_value_from_default(default) + # This is a performance optimization for Ruby 1.9.2 in development. + # If the value is nil, we return nil straight away without checking + # the regular expressions. If we check each regular expression, + # Regexp#=== will call NilClass#to_str, which will trigger + # method_missing (defined by whiny nil in ActiveSupport) which + # makes this method very very slow. + return default unless default + + case default + when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m + $1 + # Numeric types + when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/ + $1 + # Character types + when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m + $1.gsub(/''/, "'") + # Binary data types + when /\A'(.*)'::bytea\z/m + $1 + # Date/time types + when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/ + $1 + when /\A'(.*)'::interval\z/ + $1 + # Boolean type + when 'true' + true + when 'false' + false + # Geometric types + when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/ + $1 + # Network address types + when /\A'(.*)'::(?:cidr|inet|macaddr)\z/ + $1 + # Bit string types + when /\AB'(.*)'::"?bit(?: varying)?"?\z/ + $1 + # XML type + when /\A'(.*)'::xml\z/m + $1 + # Arrays + when /\A'(.*)'::"?\D+"?\[\]\z/ + $1 + # Hstore + when /\A'(.*)'::hstore\z/ + $1 + # JSON + when /\A'(.*)'::json\z/ + $1 + # Object identifier types + when /\A-?\d+\z/ + $1 + else + # Anything else is blank, some user type, or some function + # and we can't know the value of that, so return nil. + nil + end + end + + def type_cast_for_write(value) + if @oid_type.respond_to?(:type_cast_for_write) + @oid_type.type_cast_for_write(value) + else + super + end + end + + def type_cast(value) + return if value.nil? + return super if encoded? + + @oid_type.type_cast value + end + + def accessor + @oid_type.accessor + end + + private + + def has_default_function?(default_value, default) + !default_value && (%r{\w+\(.*\)} === default) + end + + def extract_limit(sql_type) + case sql_type + when /^bigint/i; 8 + when /^smallint/i; 2 + when /^timestamp/i; nil + else super + end + end + + # Extracts the scale from PostgreSQL-specific data types. + def extract_scale(sql_type) + # Money type has a fixed scale of 2. + sql_type =~ /^money/ ? 2 : super + end + + # Extracts the precision from PostgreSQL-specific data types. + def extract_precision(sql_type) + if sql_type == 'money' + self.class.money_precision + elsif sql_type =~ /timestamp/i + $1.to_i if sql_type =~ /\((\d+)\)/ + else + super + end + end + + # Maps PostgreSQL-specific data types to logical Rails types. + def simplified_type(field_type) + case field_type + # Numeric and monetary types + when /^(?:real|double precision)$/ + :float + # Monetary types + when 'money' + :decimal + when 'hstore' + :hstore + when 'ltree' + :ltree + # Network address types + when 'inet' + :inet + when 'cidr' + :cidr + when 'macaddr' + :macaddr + # Character types + when /^(?:character varying|bpchar)(?:\(\d+\))?$/ + :string + when /^citext(?:\(\d+\))?$/ + :citext + # Binary data types + when 'bytea' + :binary + # Date/time types + when /^timestamp with(?:out)? time zone$/ + :datetime + when /^interval(?:|\(\d+\))$/ + :string + # Geometric types + when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ + :string + # Bit strings + when /^bit(?: varying)?(?:\(\d+\))?$/ + :string + # XML type + when 'xml' + :xml + # tsvector type + when 'tsvector' + :tsvector + # Arrays + when /^\D+\[\]$/ + :string + # Object identifier types + when 'oid' + :integer + # UUID type + when 'uuid' + :uuid + # JSON type + when 'json' + :json + # Small and big integer types + when /^(?:small|big)int$/ + :integer + when /(num|date|tstz|ts|int4|int8)range$/ + field_type.to_sym + # Pass through all types that are not specific to PostgreSQL. + else + super + end + end + end + end +end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index bcad9f30d7..c31fe96842 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -7,6 +7,7 @@ require 'active_record/connection_adapters/postgresql/quoting' require 'active_record/connection_adapters/postgresql/schema_statements' require 'active_record/connection_adapters/postgresql/database_statements' require 'active_record/connection_adapters/postgresql/referential_integrity' +require 'active_record/connection_adapters/postgresql/column' require 'arel/visitors/bind_visitor' # Make sure we're using pg high enough for PGResult#values @@ -43,224 +44,6 @@ module ActiveRecord end module ConnectionAdapters - # PostgreSQL-specific extensions to column definitions in a table. - class PostgreSQLColumn < Column #:nodoc: - attr_accessor :array - - def initialize(name, default, oid_type, sql_type = nil, null = true) - @oid_type = oid_type - default_value = self.class.extract_value_from_default(default) - - if sql_type =~ /\[\]$/ - @array = true - super(name, default_value, sql_type[0..sql_type.length - 3], null) - else - @array = false - super(name, default_value, sql_type, null) - end - - @default_function = default if has_default_function?(default_value, default) - end - - def number? - !array && super - end - - def text? - !array && super - end - - # :stopdoc: - class << self - include ConnectionAdapters::PostgreSQLColumn::Cast - include ConnectionAdapters::PostgreSQLColumn::ArrayParser - attr_accessor :money_precision - end - # :startdoc: - - # Extracts the value from a PostgreSQL column default definition. - def self.extract_value_from_default(default) - # This is a performance optimization for Ruby 1.9.2 in development. - # If the value is nil, we return nil straight away without checking - # the regular expressions. If we check each regular expression, - # Regexp#=== will call NilClass#to_str, which will trigger - # method_missing (defined by whiny nil in ActiveSupport) which - # makes this method very very slow. - return default unless default - - case default - when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m - $1 - # Numeric types - when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/ - $1 - # Character types - when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m - $1.gsub(/''/, "'") - # Binary data types - when /\A'(.*)'::bytea\z/m - $1 - # Date/time types - when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/ - $1 - when /\A'(.*)'::interval\z/ - $1 - # Boolean type - when 'true' - true - when 'false' - false - # Geometric types - when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/ - $1 - # Network address types - when /\A'(.*)'::(?:cidr|inet|macaddr)\z/ - $1 - # Bit string types - when /\AB'(.*)'::"?bit(?: varying)?"?\z/ - $1 - # XML type - when /\A'(.*)'::xml\z/m - $1 - # Arrays - when /\A'(.*)'::"?\D+"?\[\]\z/ - $1 - # Hstore - when /\A'(.*)'::hstore\z/ - $1 - # JSON - when /\A'(.*)'::json\z/ - $1 - # Object identifier types - when /\A-?\d+\z/ - $1 - else - # Anything else is blank, some user type, or some function - # and we can't know the value of that, so return nil. - nil - end - end - - def type_cast_for_write(value) - if @oid_type.respond_to?(:type_cast_for_write) - @oid_type.type_cast_for_write(value) - else - super - end - end - - def type_cast(value) - return if value.nil? - return super if encoded? - - @oid_type.type_cast value - end - - def accessor - @oid_type.accessor - end - - private - - def has_default_function?(default_value, default) - !default_value && (%r{\w+\(.*\)} === default) - end - - def extract_limit(sql_type) - case sql_type - when /^bigint/i; 8 - when /^smallint/i; 2 - when /^timestamp/i; nil - else super - end - end - - # Extracts the scale from PostgreSQL-specific data types. - def extract_scale(sql_type) - # Money type has a fixed scale of 2. - sql_type =~ /^money/ ? 2 : super - end - - # Extracts the precision from PostgreSQL-specific data types. - def extract_precision(sql_type) - if sql_type == 'money' - self.class.money_precision - elsif sql_type =~ /timestamp/i - $1.to_i if sql_type =~ /\((\d+)\)/ - else - super - end - end - - # Maps PostgreSQL-specific data types to logical Rails types. - def simplified_type(field_type) - case field_type - # Numeric and monetary types - when /^(?:real|double precision)$/ - :float - # Monetary types - when 'money' - :decimal - when 'hstore' - :hstore - when 'ltree' - :ltree - # Network address types - when 'inet' - :inet - when 'cidr' - :cidr - when 'macaddr' - :macaddr - # Character types - when /^(?:character varying|bpchar)(?:\(\d+\))?$/ - :string - when /^citext(?:\(\d+\))?$/ - :citext - # Binary data types - when 'bytea' - :binary - # Date/time types - when /^timestamp with(?:out)? time zone$/ - :datetime - when /^interval(?:|\(\d+\))$/ - :string - # Geometric types - when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ - :string - # Bit strings - when /^bit(?: varying)?(?:\(\d+\))?$/ - :string - # XML type - when 'xml' - :xml - # tsvector type - when 'tsvector' - :tsvector - # Arrays - when /^\D+\[\]$/ - :string - # Object identifier types - when 'oid' - :integer - # UUID type - when 'uuid' - :uuid - # JSON type - when 'json' - :json - # Small and big integer types - when /^(?:small|big)int$/ - :integer - when /(num|date|tstz|ts|int4|int8)range$/ - field_type.to_sym - # Pass through all types that are not specific to PostgreSQL. - else - super - end - end - end - # The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver. # # Options: -- cgit v1.2.3 From 21a674a028a9c02b8bba81db0bfe426843ee30a9 Mon Sep 17 00:00:00 2001 From: Arthur Neves Date: Mon, 31 Mar 2014 14:45:34 -0400 Subject: Fix release task Add a parentheses. related: b4c96490eeb1fbb944e116c7703dd528b37fc08a --- tasks/release.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/release.rb b/tasks/release.rb index 849117884c..767feaf236 100644 --- a/tasks/release.rb +++ b/tasks/release.rb @@ -67,7 +67,7 @@ end namespace :changelog do task :release_date do - FRAMEWORKS + ['guides'].each do |fw| + (FRAMEWORKS + ['guides']).each do |fw| require 'date' replace = '\1(' + Date.today.strftime('%B %d, %Y') + ')' fname = File.join fw, 'CHANGELOG.md' @@ -78,7 +78,7 @@ namespace :changelog do end task :release_summary do - FRAMEWORKS + ['guides'].each do |fw| + (FRAMEWORKS + ['guides']).each do |fw| puts "## #{fw}" fname = File.join fw, 'CHANGELOG.md' contents = File.readlines fname -- cgit v1.2.3 From 95692c6179f987db84bb358de9091cc51a2736e0 Mon Sep 17 00:00:00 2001 From: Laura Paredes Date: Mon, 31 Mar 2014 20:51:13 +0200 Subject: Add test for selected and disabled custom attributes in options_for_select --- .../test/template/form_options_helper_test.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb index 50e9d132a7..fbafb7aa08 100644 --- a/actionview/test/template/form_options_helper_test.rb +++ b/actionview/test/template/form_options_helper_test.rb @@ -119,6 +119,26 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_array_options_for_select_with_custom_defined_selected + assert_dom_equal( + "\n", + options_for_select([ + ['Richard Bandler', 1, { type: 'Coach', selected: 'selected' }], + ['Richard Bandler', 1, { type: 'Coachee' }] + ]) + ) + end + + def test_array_options_for_select_with_custom_defined_disabled + assert_dom_equal( + "\n", + options_for_select([ + ['Richard Bandler', 1, { type: 'Coach', disabled: 'disabled' }], + ['Richard Bandler', 1, { type: 'Coachee' }] + ]) + ) + end + def test_array_options_for_select_with_selection assert_dom_equal( "\n\n", @@ -813,7 +833,7 @@ class FormOptionsHelperTest < ActionView::TestCase select("post", "category", %w( one two ), :selected => 'two', :prompt => true) ) end - + def test_select_with_disabled_array @post = Post.new @post.category = "" -- cgit v1.2.3 From a67293638e0c9022e69b67ae89bc5bca70f70efd Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 31 Mar 2014 19:18:04 -0400 Subject: add capture_sql method to compare sql statements and compare Other methods compare specific patterns, this method outputs the actual sql query that is generated. --- activerecord/test/cases/test_case.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index 4476ce3410..cbf6ea36bf 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -19,6 +19,12 @@ module ActiveRecord end end + def capture_sql + SQLCounter.clear_log + yield + SQLCounter.log_all.dup + end + def assert_sql(*patterns_to_match) SQLCounter.clear_log yield -- cgit v1.2.3 From a116afe5365dfaa3e5f98749f98090872c7aaecc Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 31 Mar 2014 19:25:31 -0400 Subject: add test to compare sql statements in delete_all query delete_all sql if an association is not loaded should behave the same as if the association is loaded. This test ensures the SQL statements are exactly the same. --- .../cases/associations/has_many_associations_test.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 49d3301044..3dfb0a27ba 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -22,6 +22,8 @@ require 'models/engine' require 'models/categorization' require 'models/minivan' require 'models/speedometer' +require 'models/reference' +require 'models/job' class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase fixtures :authors, :posts, :comments @@ -39,7 +41,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :categories, :companies, :developers, :projects, :developers_projects, :topics, :authors, :comments, :people, :posts, :readers, :taggings, :cars, :essays, - :categorizations + :categorizations, :jobs def setup Client.destroyed_client_ids.clear @@ -107,6 +109,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategy" end + def test_delete_all_on_association_is_the_same_as_not_loaded + author = authors :david + author.thinking_posts.create!(:body => "test") + author.reload + expected_sql = capture_sql { author.thinking_posts.delete_all } + + author.thinking_posts.create!(:body => "test") + author.reload + author.thinking_posts.inspect + loaded_sql = capture_sql { author.thinking_posts.delete_all } + assert_equal(expected_sql, loaded_sql) + end + def test_building_the_associated_object_with_implicit_sti_base_class firm = DependentFirm.new company = firm.companies.build -- cgit v1.2.3 From e247f3257927e008ed89944249ac38a8838f719f Mon Sep 17 00:00:00 2001 From: eileencodes Date: Wed, 26 Mar 2014 10:06:13 -0400 Subject: fix delete_all to remove records directly When delete_all is run on a CollectionProxy and has a dependency of delete_all the SQL that is produced has an IN statement. (DELETE FROM `associated_model` where `associated_model` .`parent_id` = 1 AND `associated_model`.`id` IN (1, 2, 3...)). This only happens if the association is not loaded (both loaded and non-loaded delete_all should behave the same. This is a huge problem when it comes to deleting many records because the query becomes very slow. Instead the SQL produced should be (DELETE FROM `assoicated_model` where `associated_model`.`parent_model_id`=1). I fixed this by making sure the check for loaded and destroy also makes sure that the dependent is not delete_all, so the conditional goes to the else and deletes the records directly without the IN statement. --- activerecord/lib/active_record/associations/collection_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 1f314e0677..80ae38b3fb 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -248,7 +248,7 @@ module ActiveRecord dependent = _options[:dependent] || options[:dependent] if records.first == :all - if loaded? || dependent == :destroy + if (loaded? || dependent == :destroy) && dependent != :delete_all delete_or_destroy(load_target, dependent) else delete_records(:all, dependent) -- cgit v1.2.3 From 6df507e884baa8566b685bb1c555e42185570160 Mon Sep 17 00:00:00 2001 From: Pavel Pravosud Date: Mon, 31 Mar 2014 22:33:53 -0400 Subject: Make AS::SafeBuffer#prepend act like String#prepend Make `#prepend` method modify instance in-place and return self instead of just returning modified value. That is exactly what `#prepend!` method was doing previously, so it's deprecated from now on. --- activesupport/CHANGELOG.md | 6 ++++++ .../core_ext/string/output_safety.rb | 19 +++++++++++++------ activesupport/test/core_ext/string_ext_test.rb | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 556e94d184..f65d9ea120 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,9 @@ +* `ActiveSupport::SafeBuffer#prepend` acts like `String#prepend` and modifies + instance in-place, returning self. `ActiveSupport::SafeBuffer#prepend!` is + deprecated. + + *Pavel Pravosud* + * `HashWithIndifferentAccess` better respects `#to_hash` on objects it's given. In particular, `.new`, `#update`, `#merge`, `#replace` all accept objects which respond to `#to_hash`, even if those objects are not Hashes diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index eb02b6a442..db80cfa737 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -124,7 +124,7 @@ module ActiveSupport #:nodoc: class SafeBuffer < String UNSAFE_STRING_METHODS = %w( capitalize chomp chop delete downcase gsub lstrip next reverse rstrip - slice squeeze strip sub succ swapcase tr tr_s upcase prepend + slice squeeze strip sub succ swapcase tr tr_s upcase ) alias_method :original_concat, :concat @@ -169,15 +169,22 @@ module ActiveSupport #:nodoc: self[0, 0] end - def concat(value) - if !html_safe? || value.html_safe? - super(value) - else - super(ERB::Util.h(value)) + %w[concat prepend].each do |method_name| + define_method method_name do |value| + if !html_safe? || value.html_safe? + super(value) + else + super(ERB::Util.h(value)) + end end end alias << concat + def prepend!(value) + ActiveSupport::Deprecation.deprecation_warning "ActiveSupport::SafeBuffer#prepend!", :prepend + prepend value + end + def +(other) dup.concat(other) end diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 072b970a2d..4a7c2dac39 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -4,6 +4,7 @@ require 'abstract_unit' require 'inflector_test_cases' require 'constantize_test_cases' +require 'active_support/deprecation/reporting' require 'active_support/inflector' require 'active_support/core_ext/string' require 'active_support/time' @@ -608,6 +609,27 @@ class OutputSafetyTest < ActiveSupport::TestCase assert !@other_combination.html_safe? end + test "Prepending safe onto unsafe yields unsafe" do + @string.prepend "other".html_safe + assert !@string.html_safe? + assert_equal @string, "otherhello" + end + + test "Prepending unsafe onto safe yields escaped safe" do + other = "other".html_safe + other.prepend "" + assert other.html_safe? + assert_equal other, "<foo>other" + end + + test "Deprecated #prepend! method is still present" do + ActiveSupport::Deprecation.silence do + other = "other".html_safe + other.prepend! "" + assert_equal other, "<foo>other" + end + end + test "Concatting safe onto unsafe yields unsafe" do @other_string = "other" -- cgit v1.2.3 From 49e17431ca3de23d68f33b7976b0c9243b1cb36e Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 31 Mar 2014 22:53:45 -0400 Subject: refactor assert_sql query to reuse capture_sql set assert_sql to reuse the capture_sql method from above instead of repeating the code in response to comments on issue #14546 --- activerecord/test/cases/test_case.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index cbf6ea36bf..803a054d7e 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -26,9 +26,7 @@ module ActiveRecord end def assert_sql(*patterns_to_match) - SQLCounter.clear_log - yield - SQLCounter.log_all + capture_sql { yield } ensure failed_patterns = [] patterns_to_match.each do |pattern| -- cgit v1.2.3 From 4d344bb4fdc0a57aff60c755dda0c5e3c6e08cdb Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Wed, 26 Mar 2014 17:14:05 +0100 Subject: PostgreSQL determine `Column#type` through corresponding OID. #7814 I ran the whole test suite and compared the old to the new types. Following is the list of types that did change with this patch: ``` DIFFERENT TYPE FOR mood: NEW: enum, BEFORE: DIFFERENT TYPE FOR floatrange: NEW: floatrange, BEFORE: float ``` The `floatrange` is a custom type. The old type `float` was simply a coincidence form the name `floatrange` and our type-guessing. --- activerecord/CHANGELOG.md | 8 ++ .../connection_adapters/postgresql/column.rb | 65 +---------- .../connection_adapters/postgresql/oid.rb | 127 +++++++++++++++------ .../test/cases/adapters/postgresql/enum_test.rb | 3 +- .../test/cases/adapters/postgresql/quoting_test.rb | 4 +- activerecord/test/cases/column_definition_test.rb | 4 +- 6 files changed, 104 insertions(+), 107 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 18ec203fa3..0235e652d3 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* PostgreSQL `Column#type` is now determined through the corresponding OID. + The column types stay the same except for enum columns. They no longer have + `nil` as type but `enum`. + + See #7814. + + *Yves Senn* + * Fixed error when specifying a non-empty default value on a PostgreSQL array column. Fixes #10613. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb index 823189934d..2cbcd5fd50 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -151,70 +151,7 @@ module ActiveRecord # Maps PostgreSQL-specific data types to logical Rails types. def simplified_type(field_type) - case field_type - # Numeric and monetary types - when /^(?:real|double precision)$/ - :float - # Monetary types - when 'money' - :decimal - when 'hstore' - :hstore - when 'ltree' - :ltree - # Network address types - when 'inet' - :inet - when 'cidr' - :cidr - when 'macaddr' - :macaddr - # Character types - when /^(?:character varying|bpchar)(?:\(\d+\))?$/ - :string - when /^citext(?:\(\d+\))?$/ - :citext - # Binary data types - when 'bytea' - :binary - # Date/time types - when /^timestamp with(?:out)? time zone$/ - :datetime - when /^interval(?:|\(\d+\))$/ - :string - # Geometric types - when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ - :string - # Bit strings - when /^bit(?: varying)?(?:\(\d+\))?$/ - :string - # XML type - when 'xml' - :xml - # tsvector type - when 'tsvector' - :tsvector - # Arrays - when /^\D+\[\]$/ - :string - # Object identifier types - when 'oid' - :integer - # UUID type - when 'uuid' - :uuid - # JSON type - when 'json' - :json - # Small and big integer types - when /^(?:small|big)int$/ - :integer - when /(num|date|tstz|ts|int4|int8)range$/ - field_type.to_sym - # Pass through all types that are not specific to PostgreSQL. - else - super - end + @oid_type.simplified_type(field_type) || super end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 5d32aaed50..57bdc3bb19 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -6,6 +6,7 @@ module ActiveRecord module OID class Type def type; end + def simplified_type(sql_type); type end def infinity(options = {}) ::Float::INFINITY * (options[:negative] ? -1 : 1) @@ -18,7 +19,9 @@ module ActiveRecord end end - class Text < Type + class String < Type + def type; :string end + def type_cast(value) return if value.nil? @@ -26,9 +29,23 @@ module ActiveRecord end end + class SpecializedString < OID::String + def type; @type end + + def initialize(type) + @type = type + end + end + + class Text < OID::String + def type; :text end + end + class Bit < Type + def type; :string end + def type_cast(value) - if String === value + if ::String === value ConnectionAdapters::PostgreSQLColumn.string_to_bit value else value @@ -37,6 +54,8 @@ module ActiveRecord end class Bytea < Type + def type; :binary end + def type_cast(value) return if value.nil? PGconn.unescape_bytea value @@ -44,9 +63,11 @@ module ActiveRecord end class Money < Type + def type; :decimal end + def type_cast(value) return if value.nil? - return value unless String === value + return value unless ::String === value # Because money output is formatted according to the locale, there are two # cases to consider (note the decimal separators): @@ -88,8 +109,10 @@ module ActiveRecord end class Point < Type + def type; :string end + def type_cast(value) - if String === value + if ::String === value ConnectionAdapters::PostgreSQLColumn.string_to_point value else value @@ -98,13 +121,15 @@ module ActiveRecord end class Array < Type + def type; @subtype.type end + attr_reader :subtype def initialize(subtype) @subtype = subtype end def type_cast(value) - if String === value + if ::String === value ConnectionAdapters::PostgreSQLColumn.string_to_array value, @subtype else value @@ -114,6 +139,8 @@ module ActiveRecord class Range < Type attr_reader :subtype + def simplified_type(sql_type); sql_type.to_sym end + def initialize(subtype) @subtype = subtype end @@ -160,6 +187,8 @@ This is not reliable and will be removed in the future. end class Integer < Type + def type; :integer end + def type_cast(value) return if value.nil? @@ -168,6 +197,8 @@ This is not reliable and will be removed in the future. end class Boolean < Type + def type; :boolean end + def type_cast(value) return if value.nil? @@ -177,6 +208,14 @@ This is not reliable and will be removed in the future. class Timestamp < Type def type; :timestamp; end + def simplified_type(sql_type) + case sql_type + when /^timestamp with(?:out)? time zone$/ + :datetime + else + :timestamp + end + end def type_cast(value) return if value.nil? @@ -188,7 +227,7 @@ This is not reliable and will be removed in the future. end class Date < Type - def type; :datetime; end + def type; :date; end def type_cast(value) return if value.nil? @@ -200,6 +239,8 @@ This is not reliable and will be removed in the future. end class Time < Type + def type; :time end + def type_cast(value) return if value.nil? @@ -210,6 +251,8 @@ This is not reliable and will be removed in the future. end class Float < Type + def type; :float end + def type_cast(value) return if value.nil? @@ -218,6 +261,8 @@ This is not reliable and will be removed in the future. end class Decimal < Type + def type; :decimal end + def type_cast(value) return if value.nil? @@ -230,12 +275,16 @@ This is not reliable and will be removed in the future. end class Enum < Type + def type; :enum end + def type_cast(value) value.to_s end end class Hstore < Type + def type; :hstore end + def type_cast_for_write(value) ConnectionAdapters::PostgreSQLColumn.hstore_to_string value end @@ -252,14 +301,20 @@ This is not reliable and will be removed in the future. end class Cidr < Type + def type; :cidr end def type_cast(value) return if value.nil? ConnectionAdapters::PostgreSQLColumn.string_to_cidr value end end + class Inet < Cidr + def type; :inet end + end class Json < Type + def type; :json end + def type_cast_for_write(value) ConnectionAdapters::PostgreSQLColumn.json_to_string value end @@ -321,7 +376,7 @@ This is not reliable and will be removed in the future. } # Register an OID type named +name+ with a typecasting object in - # +type+. +name+ should correspond to the `typname` column in + # +type+. +name+ should correspond to the `typname` column in # the `pg_type` table. def self.register_type(name, type) NAMES[name] = type @@ -338,48 +393,46 @@ This is not reliable and will be removed in the future. end register_type 'int2', OID::Integer.new - alias_type 'int4', 'int2' - alias_type 'int8', 'int2' - alias_type 'oid', 'int2' - + alias_type 'int4', 'int2' + alias_type 'int8', 'int2' + alias_type 'oid', 'int2' register_type 'numeric', OID::Decimal.new + register_type 'float4', OID::Float.new + alias_type 'float8', 'float4' register_type 'text', OID::Text.new - alias_type 'varchar', 'text' - alias_type 'char', 'text' - alias_type 'bpchar', 'text' - alias_type 'xml', 'text' - - # FIXME: why are we keeping these types as strings? - alias_type 'tsvector', 'text' - alias_type 'interval', 'text' - alias_type 'macaddr', 'text' - alias_type 'uuid', 'text' - - register_type 'money', OID::Money.new - register_type 'bytea', OID::Bytea.new + register_type 'varchar', OID::String.new + alias_type 'char', 'varchar' + alias_type 'bpchar', 'varchar' register_type 'bool', OID::Boolean.new register_type 'bit', OID::Bit.new - register_type 'varbit', OID::Bit.new - - register_type 'float4', OID::Float.new - alias_type 'float8', 'float4' - + alias_type 'varbit', 'bit' register_type 'timestamp', OID::Timestamp.new - register_type 'timestamptz', OID::Timestamp.new + alias_type 'timestamptz', 'timestamp' register_type 'date', OID::Date.new register_type 'time', OID::Time.new - register_type 'path', OID::Text.new + register_type 'money', OID::Money.new + register_type 'bytea', OID::Bytea.new register_type 'point', OID::Point.new - register_type 'polygon', OID::Text.new - register_type 'circle', OID::Text.new register_type 'hstore', OID::Hstore.new register_type 'json', OID::Json.new - register_type 'citext', OID::Text.new - register_type 'ltree', OID::Text.new - register_type 'cidr', OID::Cidr.new - alias_type 'inet', 'cidr' + register_type 'inet', OID::Inet.new + register_type 'xml', SpecializedString.new(:xml) + register_type 'tsvector', SpecializedString.new(:tsvector) + register_type 'macaddr', SpecializedString.new(:macaddr) + register_type 'uuid', SpecializedString.new(:uuid) + register_type 'citext', SpecializedString.new(:citext) + register_type 'ltree', SpecializedString.new(:ltree) + + # FIXME: why are we keeping these types as strings? + alias_type 'interval', 'varchar' + alias_type 'path', 'varchar' + alias_type 'line', 'varchar' + alias_type 'polygon', 'varchar' + alias_type 'circle', 'varchar' + alias_type 'lseg', 'varchar' + alias_type 'box', 'varchar' end end end diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index 381c397922..ac78c2426e 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -29,8 +29,7 @@ class PostgresqlEnumTest < ActiveRecord::TestCase def test_column column = PostgresqlEnum.columns_hash["current_mood"] - # TODO: enum columns should be of type enum or string, not nil. - assert_nil column.type + assert_equal :enum, column.type assert_equal "mood", column.sql_type assert_not column.number? assert_not column.text? diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 39f5b9b18a..51846e22d9 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -47,9 +47,9 @@ module ActiveRecord def test_quote_cast_numeric fixnum = 666 - c = PostgreSQLColumn.new(nil, nil, OID::Decimal.new, 'varchar') + c = PostgreSQLColumn.new(nil, nil, OID::String.new, 'varchar') assert_equal "'666'", @conn.quote(fixnum, c) - c = PostgreSQLColumn.new(nil, nil, OID::Decimal.new, 'text') + c = PostgreSQLColumn.new(nil, nil, OID::Text.new, 'text') assert_equal "'666'", @conn.quote(fixnum, c) end diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index c7b64f29c3..c1dd1f1c69 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -127,13 +127,13 @@ module ActiveRecord if current_adapter?(:PostgreSQLAdapter) def test_bigint_column_should_map_to_integer - oid = PostgreSQLAdapter::OID::Identity.new + oid = PostgreSQLAdapter::OID::Integer.new bigint_column = PostgreSQLColumn.new('number', nil, oid, "bigint") assert_equal :integer, bigint_column.type end def test_smallint_column_should_map_to_integer - oid = PostgreSQLAdapter::OID::Identity.new + oid = PostgreSQLAdapter::OID::Integer.new smallint_column = PostgreSQLColumn.new('number', nil, oid, "smallint") assert_equal :integer, smallint_column.type end -- cgit v1.2.3 From f7a6b115fea9f675190a79b701c7034214678f19 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Tue, 1 Apr 2014 19:42:22 +0200 Subject: PostgreSQL, register custom domains. Closes #14305. This patch registers custom domains in our OID-type_map. They will behave exactly as the type specified by `pg_type.typbasetype`. /cc @matthewd --- activerecord/CHANGELOG.md | 4 ++ .../connection_adapters/postgresql_adapter.rb | 12 ++++- .../test/cases/adapters/postgresql/domain_test.rb | 53 ++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 activerecord/test/cases/adapters/postgresql/domain_test.rb diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 0235e652d3..1aeba4f856 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* The PostgreSQL adapter supports custom domains. Fixes #14305. + + *Yves Senn* + * PostgreSQL `Column#type` is now determined through the corresponding OID. The column types stay the same except for enum columns. They no longer have `nil` as type but `enum`. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index c31fe96842..e8719d5269 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -582,7 +582,7 @@ module ActiveRecord def initialize_type_map(type_map) if supports_ranges? result = execute(<<-SQL, 'SCHEMA') - SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype + SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype FROM pg_type as t LEFT JOIN pg_range as r ON oid = rngtypid SQL @@ -593,6 +593,7 @@ module ActiveRecord SQL end ranges, nodes = result.partition { |row| row['typinput'] == 'range_in' } + domains, nodes = nodes.partition { |row| row['typtype'] == 'd' } leaves, nodes = nodes.partition { |row| row['typelem'] == '0' } arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' } @@ -626,6 +627,15 @@ module ActiveRecord range = OID::Range.new subtype type_map[row['oid'].to_i] = range end + + # populate domain types + domains.each do |row| + if base_type = type_map[row["typbasetype"].to_i] + type_map[row['oid'].to_i] = base_type + else + warn "unknown base type (OID: #{row["typbasetype"].to_i}) for domain #{row["typname"]}." + end + end end FEATURE_NOT_SUPPORTED = "0A000" #:nodoc: diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb new file mode 100644 index 0000000000..fdf5ce974d --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +require "cases/helper" +require 'active_record/base' +require 'active_record/connection_adapters/postgresql_adapter' + +class PostgresqlDomainTest < ActiveRecord::TestCase + class PostgresqlDomain < ActiveRecord::Base + self.table_name = "postgresql_domains" + end + + def setup + # reset connection to bust all cached statement plans + connection_spec = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(connection_spec) + + @connection = ActiveRecord::Base.connection + @connection.transaction do + @connection.execute "CREATE DOMAIN custom_money as numeric(8,2)" + @connection.create_table('postgresql_domains') do |t| + t.column :price, :custom_money + end + end + + # reload type map after creating the enum type + @connection.send(:reload_type_map) + end + + teardown do + @connection.execute 'DROP TABLE IF EXISTS postgresql_domains' + @connection.execute 'DROP DOMAIN IF EXISTS custom_money' + end + + def test_column + column = PostgresqlDomain.columns_hash["price"] + assert_equal :decimal, column.type + assert_equal "custom_money", column.sql_type + assert column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_domain_acts_like_basetype + PostgresqlDomain.create price: "" + record = PostgresqlDomain.first + assert_nil record.price + + record.price = "34.15" + record.save! + + assert_equal BigDecimal.new("34.15"), record.reload.price + end +end -- cgit v1.2.3 From 06082f66d541e581110406bbac3bc395bace3f86 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Tue, 1 Apr 2014 19:56:34 +0200 Subject: refactor, use `typtype` instead of `typinput` to segment PG types. --- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e8719d5269..0b29f4ca16 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -592,13 +592,13 @@ module ActiveRecord FROM pg_type as t SQL end - ranges, nodes = result.partition { |row| row['typinput'] == 'range_in' } + ranges, nodes = result.partition { |row| row['typtype'] == 'r' } + enums, nodes = nodes.partition { |row| row['typtype'] == 'e' } domains, nodes = nodes.partition { |row| row['typtype'] == 'd' } - leaves, nodes = nodes.partition { |row| row['typelem'] == '0' } arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' } + leaves, nodes = nodes.partition { |row| row['typelem'] == '0' } # populate the enum types - enums, leaves = leaves.partition { |row| row['typinput'] == 'enum_in' } enums.each do |row| type_map[row['oid'].to_i] = OID::Enum.new end -- cgit v1.2.3 From 5d0a4e0cb6134b86fc2795047aacb335c978e02e Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Tue, 1 Apr 2014 23:41:25 +0200 Subject: fix, adjust OID query without range support to include required fields. This is a follow-up fix to f7a6b115fea9f675190a79b701c7034214678f19 and 06082f66d541e581110406bbac3bc395bace3f86 --- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 0b29f4ca16..e17558bdeb 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -588,7 +588,7 @@ module ActiveRecord SQL else result = execute(<<-SQL, 'SCHEMA') - SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput + SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype FROM pg_type as t SQL end @@ -630,10 +630,11 @@ module ActiveRecord # populate domain types domains.each do |row| - if base_type = type_map[row["typbasetype"].to_i] + base_type_oid = row["typbasetype"].to_i + if base_type = type_map[base_type_oid] type_map[row['oid'].to_i] = base_type else - warn "unknown base type (OID: #{row["typbasetype"].to_i}) for domain #{row["typname"]}." + warn "unknown base type (OID: #{base_type_oid}) for domain #{row["typname"]}." end end end -- cgit v1.2.3 From 9aa7c25c28325f62815b6625bdfcc6dd7565165b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 1 Apr 2014 16:45:15 -0500 Subject: Clarify 'database does not exist' message and implementation. * Clarify what the situation is and what to do. * Advise loading schema using `rake db:setup` instead of migrating. * Use a rescue in the initializer rather than extending the error message in-place. * Preserve the original backtrace of other errors by using `raise` rather than raising again with `raise error`. References 0ec45cd15d0a2f5aebc75e23d841b6c12f3ba763 --- .../connection_adapters/mysql2_adapter.rb | 4 ++-- .../connection_adapters/mysql_adapter.rb | 4 ++-- .../connection_adapters/postgresql_adapter.rb | 4 ++-- .../connection_adapters/sqlite3_adapter.rb | 4 ++-- activerecord/lib/active_record/errors.rb | 10 +--------- activerecord/lib/active_record/railtie.rb | 23 +++++++++++++--------- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 2b5049f5a5..5e82fdcbe0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -20,9 +20,9 @@ module ActiveRecord ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) rescue Mysql2::Error => error if error.message.include?("Unknown database") - raise ActiveRecord::NoDatabaseError.new(error.message) + raise ActiveRecord::NoDatabaseError.new(error.message, error) else - raise error + raise end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 49f0bfbcde..e6aa2ba921 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -36,9 +36,9 @@ module ActiveRecord ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config) rescue Mysql::Error => error if error.message.include?("Unknown database") - raise ActiveRecord::NoDatabaseError.new(error.message) + raise ActiveRecord::NoDatabaseError.new(error.message, error) else - raise error + raise end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e17558bdeb..748436de12 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -718,9 +718,9 @@ module ActiveRecord configure_connection rescue ::PG::Error => error if error.message.include?("does not exist") - raise ActiveRecord::NoDatabaseError.new(error.message) + raise ActiveRecord::NoDatabaseError.new(error.message, error) else - raise error + raise end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 3c5f7a981e..6e6a51dab8 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -33,9 +33,9 @@ module ActiveRecord ConnectionAdapters::SQLite3Adapter.new(db, logger, config) rescue Errno::ENOENT => error if error.message.include?("No such file or directory") - raise ActiveRecord::NoDatabaseError.new(error.message) + raise ActiveRecord::NoDatabaseError.new(error.message, error) else - raise error + raise end end end diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 7f6228131f..71efbb8f93 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -95,15 +95,7 @@ module ActiveRecord end # Raised when a given database does not exist - class NoDatabaseError < ActiveRecordError - def initialize(message) - super extend_message(message) - end - - # can be over written to add additional error information. - def extend_message(message) - message - end + class NoDatabaseError < StatementInvalid end # Raised on attempt to save stale record. Record is stale when it's being saved in another query after diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 11b564f8f9..a4ceacbf44 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -116,17 +116,22 @@ module ActiveRecord # and then establishes the connection. initializer "active_record.initialize_database" do |app| ActiveSupport.on_load(:active_record) do + self.configurations = Rails.application.config.database_configuration - class ActiveRecord::NoDatabaseError - remove_possible_method :extend_message - def extend_message(message) - message << "Run `$ bin/rake db:create db:migrate` to create your database" - message - end - end + begin + establish_connection + rescue ActiveRecord::NoDatabaseError + warn <<-end_warning +Oops - You have a database configured, but it doesn't exist yet! - self.configurations = Rails.application.config.database_configuration - establish_connection +Here's how to get started: + + 1. Configure your database in config/database.yml. + 2. Run `bin/rake db:create` to create the database. + 3. Run `bin/rake db:setup` to load your database schema. +end_warning + raise + end end end -- cgit v1.2.3 From d04bcf94da9a19d9470f920587f8d2055d3b7108 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 1 Apr 2014 15:50:58 -0700 Subject: only ask if `t` is empty once. --- actionpack/lib/action_dispatch/journey/gtg/transition_table.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index e6212b1ee2..53c47f4696 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -40,6 +40,7 @@ module ActionDispatch end def move(t, a) + return [] if t.empty? move_string(t, a).concat(move_regexp(t, a)) end @@ -141,8 +142,6 @@ module ActionDispatch end def move_regexp(t, a) - return [] if t.empty? - t.flat_map { |s| if states = @regexp_states[s] states.map { |re, v| re === a ? v : nil } @@ -151,8 +150,6 @@ module ActionDispatch end def move_string(t, a) - return [] if t.empty? - t.map do |s| if states = @string_states[s] states[a] -- cgit v1.2.3 From ee453a1ea1e35a0ef2f9f65a135c9e5d090b3dd2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 1 Apr 2014 15:55:48 -0700 Subject: do not create memo objects since we'll just throw them away --- actionpack/lib/action_dispatch/journey/gtg/simulator.rb | 17 ++++++++++------- actionpack/lib/action_dispatch/journey/router.rb | 3 +-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb index 254c2befc4..94b0a24344 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb @@ -19,6 +19,14 @@ module ActionDispatch end def simulate(string) + ms = memos(string) { return } + MatchData.new(ms) + end + + alias :=~ :simulate + alias :match :simulate + + def memos(string) input = StringScanner.new(string) state = [0] while sym = input.scan(%r([/.?]|[^/.?]+)) @@ -29,15 +37,10 @@ module ActionDispatch tt.accepting? s } - return if acceptance_states.empty? + return yield if acceptance_states.empty? - memos = acceptance_states.flat_map { |x| tt.memo(x) }.compact - - MatchData.new(memos) + acceptance_states.flat_map { |x| tt.memo(x) }.compact end - - alias :=~ :simulate - alias :match :simulate end end end diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index 419e665d12..36561c71a1 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -121,8 +121,7 @@ module ActionDispatch def filter_routes(path) return [] unless ast - data = simulator.match(path) - data ? data.memos : [] + simulator.memos(path) { [] } end def find_routes env -- cgit v1.2.3 From 0e53d11b1fa9712270402afce771402c45fdd645 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 1 Apr 2014 15:56:23 -0700 Subject: combine move_regexp and move_string so we only loop over states once --- .../lib/action_dispatch/journey/gtg/transition_table.rb | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index 53c47f4696..821b510b9e 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -41,7 +41,7 @@ module ActionDispatch def move(t, a) return [] if t.empty? - move_string(t, a).concat(move_regexp(t, a)) + move_string(t, a) end def as_json(options = nil) @@ -141,20 +141,17 @@ module ActionDispatch end end - def move_regexp(t, a) - t.flat_map { |s| + def move_string(t, a) + regexps = [] + t.map { |s| if states = @regexp_states[s] - states.map { |re, v| re === a ? v : nil } + regexps.concat states.map { |re, v| re === a ? v : nil } end - }.compact.uniq - end - def move_string(t, a) - t.map do |s| if states = @string_states[s] states[a] end - end.compact + }.compact.concat regexps end end end -- cgit v1.2.3 From 6c6dc329f8ca87304bce3be79f4d1172219d07ad Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 1 Apr 2014 15:58:42 -0700 Subject: push move_string in to `move` --- .../journey/gtg/transition_table.rb | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index 821b510b9e..990d2127ee 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -41,7 +41,18 @@ module ActionDispatch def move(t, a) return [] if t.empty? - move_string(t, a) + + regexps = [] + + t.map { |s| + if states = @regexp_states[s] + regexps.concat states.map { |re, v| re === a ? v : nil } + end + + if states = @string_states[s] + states[a] + end + }.compact.concat regexps end def as_json(options = nil) @@ -140,19 +151,6 @@ module ActionDispatch raise ArgumentError, 'unknown symbol: %s' % sym.class end end - - def move_string(t, a) - regexps = [] - t.map { |s| - if states = @regexp_states[s] - regexps.concat states.map { |re, v| re === a ? v : nil } - end - - if states = @string_states[s] - states[a] - end - }.compact.concat regexps - end end end end -- cgit v1.2.3 From 90aef2814c874eef96c7645b3ee7bdc35731f4a2 Mon Sep 17 00:00:00 2001 From: Benjamin Winkler Date: Wed, 2 Apr 2014 00:31:52 -0400 Subject: Changed 'so' to 'see' --- RELEASING_RAILS.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index 9b06d0d162..c6c1c12e87 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -158,7 +158,7 @@ commits should be added to the release branch besides regression fixing commits. == Day of release Many of these steps are the same as for the release candidate, so if you need -more explanation on a particular step, so the RC steps. +more explanation on a particular step, see the RC steps. Today, do this stuff in this order: -- cgit v1.2.3 From 9896c5fba9686524600d58e703e2aae80105043b Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Mon, 31 Mar 2014 21:53:43 -0700 Subject: Allow postgresql enum_test to be run in random order. Creating and dropping similar tables within the same connection causes postgresql to look up old values in the cache of tables which have already been dropped. --- activerecord/test/cases/adapters/postgresql/domain_test.rb | 8 ++++---- activerecord/test/cases/adapters/postgresql/enum_test.rb | 14 +++++++++----- activerecord/test/support/postgresql_helper.rb | 8 ++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 activerecord/test/support/postgresql_helper.rb diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb index fdf5ce974d..ba25a64fac 100644 --- a/activerecord/test/cases/adapters/postgresql/domain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- require "cases/helper" +require 'support/postgresql_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlDomainTest < ActiveRecord::TestCase + include PostgresqlHelper + class PostgresqlDomain < ActiveRecord::Base self.table_name = "postgresql_domains" end def setup - # reset connection to bust all cached statement plans - connection_spec = ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(connection_spec) - @connection = ActiveRecord::Base.connection @connection.transaction do @connection.execute "CREATE DOMAIN custom_money as numeric(8,2)" @@ -28,6 +27,7 @@ class PostgresqlDomainTest < ActiveRecord::TestCase teardown do @connection.execute 'DROP TABLE IF EXISTS postgresql_domains' @connection.execute 'DROP DOMAIN IF EXISTS custom_money' + reset_pg_session end def test_column diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index ac78c2426e..fde01314a5 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -1,18 +1,16 @@ # -*- coding: utf-8 -*- require "cases/helper" +require 'support/postgresql_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlEnumTest < ActiveRecord::TestCase + include PostgresqlHelper + class PostgresqlEnum < ActiveRecord::Base self.table_name = "postgresql_enums" end - teardown do - @connection.execute 'DROP TABLE IF EXISTS postgresql_enums' - @connection.execute 'DROP TYPE IF EXISTS mood' - end - def setup @connection = ActiveRecord::Base.connection @connection.transaction do @@ -27,6 +25,12 @@ class PostgresqlEnumTest < ActiveRecord::TestCase @connection.send(:reload_type_map) end + teardown do + @connection.execute 'DROP TABLE IF EXISTS postgresql_enums' + @connection.execute 'DROP TYPE IF EXISTS mood' + reset_pg_session + end + def test_column column = PostgresqlEnum.columns_hash["current_mood"] assert_equal :enum, column.type diff --git a/activerecord/test/support/postgresql_helper.rb b/activerecord/test/support/postgresql_helper.rb new file mode 100644 index 0000000000..fa40a46499 --- /dev/null +++ b/activerecord/test/support/postgresql_helper.rb @@ -0,0 +1,8 @@ +module PostgresqlHelper + # Make sure to drop all cached query plans to prevent invalid reference errors like: + # cache lookup failed for type XYZ + def reset_pg_session + original_connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(original_connection) + end +end -- cgit v1.2.3 From f159b0a5a8e0c43942e8d60eb27a51f2679afa3e Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Wed, 2 Apr 2014 09:03:48 +0200 Subject: cleanup, `reset_pg_session` in range_test.rb Also do not use transactional fixtures. We drop the type and the table after every run, so there is nothing for the transaction to clean up. --- activerecord/test/cases/adapters/postgresql/range_test.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index a9d4312fb3..b57568dbad 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'support/postgresql_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' @@ -8,17 +9,19 @@ if ActiveRecord::Base.connection.supports_ranges? end class PostgresqlRangeTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + include PostgresqlHelper + teardown do @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges' @connection.execute 'DROP TYPE IF EXISTS floatrange' + reset_pg_session end def setup @connection = PostgresqlRange.connection begin @connection.transaction do - @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges' - @connection.execute 'DROP TYPE IF EXISTS floatrange' @connection.execute <<_SQL CREATE TYPE floatrange AS RANGE ( subtype = float8, -- cgit v1.2.3 From def60710ad74132a322fe8a08b0a6f0bbd3a3eed Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sat, 30 Nov 2013 16:01:34 -0700 Subject: PostgreSQL, Support for materialized views. [Dave Lee & Yves Senn] Expand the query used in #table_exists? to include materialized views in the kinds of relations it searches. --- activerecord/CHANGELOG.md | 4 +++ .../postgresql/schema_statements.rb | 5 +--- .../connection_adapters/postgresql_adapter.rb | 4 +++ .../test/cases/adapters/postgresql/view_test.rb | 34 +++++++++++++++++----- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 1aeba4f856..acd3d395c5 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Enable support for materialized views on PostgreSQL >= 9.3. + + *Dave Lee* + * The PostgreSQL adapter supports custom domains. Fixes #14305. *Yves Senn* diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index e0afa989cd..50a73aa666 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -104,14 +104,11 @@ module ActiveRecord schema, table = Utils.extract_schema_and_table(name.to_s) return false unless table - binds = [[nil, table]] - binds << [nil, schema] if schema - exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0 SELECT COUNT(*) FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - WHERE c.relkind in ('v','r') + WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view AND c.relname = '#{table.gsub(/(^"|"$)/,'')}' AND n.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'} SQL diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 748436de12..9fe8e0497e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -454,6 +454,10 @@ module ActiveRecord postgresql_version >= 90200 end + def supports_materialized_views? + postgresql_version >= 90300 + end + def enable_extension(name) exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap { reload_type_map diff --git a/activerecord/test/cases/adapters/postgresql/view_test.rb b/activerecord/test/cases/adapters/postgresql/view_test.rb index 08071894c4..47b7d38eda 100644 --- a/activerecord/test/cases/adapters/postgresql/view_test.rb +++ b/activerecord/test/cases/adapters/postgresql/view_test.rb @@ -1,11 +1,15 @@ require "cases/helper" -class ViewTest < ActiveRecord::TestCase - self.use_transactional_fixtures = false +module ViewTestConcern + extend ActiveSupport::Concern + + included do + self.use_transactional_fixtures = false + mattr_accessor :view_type + end SCHEMA_NAME = 'test_schema' TABLE_NAME = 'things' - VIEW_NAME = 'view_things' COLUMNS = [ 'id integer', 'name character varying(50)', @@ -14,17 +18,19 @@ class ViewTest < ActiveRecord::TestCase ] class ThingView < ActiveRecord::Base - self.table_name = 'test_schema.view_things' end def setup + super + ThingView.table_name = "#{SCHEMA_NAME}.#{view_type}_things" + @connection = ActiveRecord::Base.connection @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" - @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})" - @connection.execute "CREATE VIEW #{SCHEMA_NAME}.#{VIEW_NAME} AS SELECT id,name,email,moment FROM #{SCHEMA_NAME}.#{TABLE_NAME}" + @connection.execute "CREATE #{view_type.humanize} #{ThingView.table_name} AS SELECT * FROM #{SCHEMA_NAME}.#{TABLE_NAME}" end - teardown do + def teardown + super @connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE" end @@ -35,7 +41,7 @@ class ViewTest < ActiveRecord::TestCase def test_column_definitions assert_nothing_raised do - assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{VIEW_NAME}") + assert_equal COLUMNS, columns(ThingView.table_name) end end @@ -47,3 +53,15 @@ class ViewTest < ActiveRecord::TestCase end end + +class ViewTest < ActiveRecord::TestCase + include ViewTestConcern + self.view_type = 'view' +end + +if ActiveRecord::Base.connection.supports_materialized_views? + class MaterializedViewTest < ActiveRecord::TestCase + include ViewTestConcern + self.view_type = 'materialized_view' + end +end -- cgit v1.2.3 From ee36af1b773f1a6a58ff976b95d56dcce2d3c690 Mon Sep 17 00:00:00 2001 From: Rajarshi Das Date: Wed, 2 Apr 2014 16:19:57 +0530 Subject: We can conditional define the tests depending on the adapter or connection. --- activerecord/test/cases/adapter_test.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index ed4d0d503d..90953ce6cd 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -144,9 +144,9 @@ module ActiveRecord @connection.execute "INSERT INTO subscribers(nick) VALUES('me')" end end - - def test_foreign_key_violations_are_translated_to_specific_exception - unless current_adapter?(:SQLite3Adapter) + + unless current_adapter?(:SQLite3Adapter) + def test_foreign_key_violations_are_translated_to_specific_exception assert_raises(ActiveRecord::InvalidForeignKey) do # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method if @connection.prefetch_primary_key? @@ -157,10 +157,8 @@ module ActiveRecord end end end - end - - def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false - unless current_adapter?(:SQLite3Adapter) + + def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false klass_has_fk = Class.new(ActiveRecord::Base) do self.table_name = 'fk_test_has_fk' end -- cgit v1.2.3 From 848289589edb74767cb97de9ed37a545a8d8b901 Mon Sep 17 00:00:00 2001 From: Pavel Pravosud Date: Wed, 2 Apr 2014 09:19:50 -0400 Subject: DRY AS::SafeBuffer a bit using existing helper --- activesupport/lib/active_support/core_ext/string/output_safety.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index db80cfa737..85cc75ff9a 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -171,11 +171,7 @@ module ActiveSupport #:nodoc: %w[concat prepend].each do |method_name| define_method method_name do |value| - if !html_safe? || value.html_safe? - super(value) - else - super(ERB::Util.h(value)) - end + super(html_escape_interpolated_argument(value)) end end alias << concat -- cgit v1.2.3 From 8ae3f24eb7ff630c722fbee2d1b3182b3a85f3dd Mon Sep 17 00:00:00 2001 From: Alessandro Tagliapietra Date: Wed, 2 Apr 2014 16:02:13 +0200 Subject: Fixed small documentation typo Using `Rails.application.config.cookies_serializer :hybrid` throws an exception, fixed to `=`. --- guides/source/upgrading_ruby_on_rails.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index d58024df3d..0045206c76 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -105,7 +105,7 @@ the signed and encrypted cookie jars. If you want to use the new `JSON`-based fo in your application, you can add an initializer file with the following content: ```ruby - Rails.application.config.cookies_serializer :hybrid + Rails.application.config.cookies_serializer = :hybrid ``` This would transparently migrate your existing `Marshal`-serialized cookies into the -- cgit v1.2.3 From a9752dcfd15bcddfe7b6f7126f3a6e0ba5927c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 2 Apr 2014 11:24:05 -0300 Subject: Use asert_deprecated --- activesupport/test/core_ext/string_ext_test.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 4a7c2dac39..d761a0dbd8 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -623,11 +623,13 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "Deprecated #prepend! method is still present" do - ActiveSupport::Deprecation.silence do - other = "other".html_safe + other = "other".html_safe + + assert_deprecated do other.prepend! "" - assert_equal other, "<foo>other" end + + assert_equal other, "<foo>other" end test "Concatting safe onto unsafe yields unsafe" do -- cgit v1.2.3 From f846828dae77696daea3bafd91a25a62977be481 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Wed, 2 Apr 2014 23:06:16 +1030 Subject: Revise 'sqlite3:' URL handling for smoother upgrades Restore the 4.0 behaviour for 'sqlite3:///', but deprecate it. We'll change to the absolute-path interpretation in 4.2. The current "correct" spellings for in-memory, relative, and absolute URLs, respectively, are: sqlite3::memory: sqlite3:relative/path sqlite3:/full/path Substantially reverses/defers fbb79b517f3127ba620fedd01849f9628b78d6ce. Uncovered by @guilleiguaran while investigating #14495, though that sounds like a different issue. --- activerecord/CHANGELOG.md | 17 ++++++ .../connection_specification.rb | 63 +++++++++++++++------- .../cases/adapters/sqlite3/sqlite3_adapter_test.rb | 4 +- .../connection_specification/resolver_test.rb | 27 ++++++++-- activerecord/test/cases/fixtures_test.rb | 2 +- guides/source/configuring.md | 4 +- .../app/templates/config/databases/sqlite3.yml | 6 ++- .../application/initializers/frameworks_test.rb | 4 +- railties/test/application/rake/dbs_test.rb | 4 +- 9 files changed, 98 insertions(+), 33 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index acd3d395c5..38ac8bdfeb 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,20 @@ +* (Temporarily) deprecate SQLite database URLs containing an + authority. + + The current "correct" spellings for in-memory, relative, and + absolute URLs, respectively, are: + + sqlite3::memory: + sqlite3:relative/path + sqlite3:/full/path + + The previous spelling (`sqlite3:///relative/path`) continues to work + as it did in Rails 4.0, but with a deprecation warning: in the next + release, that spelling will instead be interpreted as an absolute + path. + + *Matthew Draper* + * Enable support for materialized views on PostgreSQL >= 9.3. *Dave Lee* diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 9a133168f8..5ede946836 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -35,7 +35,13 @@ module ActiveRecord @uri = URI.parse(url) @adapter = @uri.scheme @adapter = "postgresql" if @adapter == "postgres" - @query = @uri.query || '' + + if @uri.opaque + @uri.opaque, @query = @uri.opaque.split('?', 2) + else + @query = @uri.query + end + @authority = url =~ %r{\A[^:]*://} end # Converts the given URL to a full connection hash. @@ -65,30 +71,51 @@ module ActiveRecord # "localhost" # # => {} def query_hash - Hash[@query.split("&").map { |pair| pair.split("=") }] + Hash[(@query || '').split("&").map { |pair| pair.split("=") }] end def raw_config - query_hash.merge({ - "adapter" => @adapter, - "username" => uri.user, - "password" => uri.password, - "port" => uri.port, - "database" => database, - "host" => uri.host }) + if uri.opaque + query_hash.merge({ + "adapter" => @adapter, + "database" => uri.opaque }) + else + query_hash.merge({ + "adapter" => @adapter, + "username" => uri.user, + "password" => uri.password, + "port" => uri.port, + "database" => database_from_path, + "host" => uri.host }) + end end # Returns name of the database. - # Sqlite3 expects this to be a full path or `:memory:`. - def database - if @adapter == 'sqlite3' - if '/:memory:' == uri.path - ':memory:' - else - uri.path - end + # Sqlite3's handling of a leading slash is in transition as of + # Rails 4.1. + def database_from_path + if @authority && @adapter == 'sqlite3' + # 'sqlite3:///foo' is relative, for backwards compatibility. + + database_name = uri.path.sub(%r{^/}, "") + + msg = "Paths in SQLite3 database URLs of the form `sqlite3:///path` will be treated as absolute in Rails 4.2. " \ + "Please switch to `sqlite3:#{database_name}`." + ActiveSupport::Deprecation.warn(msg) + + database_name + + elsif @adapter == 'sqlite3' + # 'sqlite3:/foo' is absolute, because that makes sense. The + # corresponding relative version, 'sqlite3:foo', is handled + # elsewhere, as an "opaque". + + uri.path else - uri.path.sub(%r{^/},"") + # Only SQLite uses a filename as the "database" name; for + # anything else, a leading slash would be silly. + + uri.path.sub(%r{^/}, "") end end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index c2a255451e..14aad61ce2 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -31,7 +31,7 @@ module ActiveRecord def test_connect_with_url original_connection = ActiveRecord::Base.remove_connection tf = Tempfile.open 'whatever' - url = "sqlite3://#{tf.path}" + url = "sqlite3:#{tf.path}" ActiveRecord::Base.establish_connection(url) assert ActiveRecord::Base.connection ensure @@ -42,7 +42,7 @@ module ActiveRecord def test_connect_memory_with_url original_connection = ActiveRecord::Base.remove_connection - url = "sqlite3:///:memory:" + url = "sqlite3::memory:" ActiveRecord::Base.establish_connection(url) assert ActiveRecord::Base.connection ensure diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb index fdd1914cba..a4fe87049a 100644 --- a/activerecord/test/cases/connection_specification/resolver_test.rb +++ b/activerecord/test/cases/connection_specification/resolver_test.rb @@ -82,15 +82,34 @@ module ActiveRecord assert_equal password, spec["password"] end - def test_url_host_db_for_sqlite3 - spec = resolve 'sqlite3://foo:bar@dburl:9000/foo_test' + def test_url_with_authority_for_sqlite3 + spec = assert_deprecated { resolve 'sqlite3:///foo_test' } + assert_equal('foo_test', spec["database"]) + end + + def test_url_absolute_path_for_sqlite3 + spec = resolve 'sqlite3:/foo_test' assert_equal('/foo_test', spec["database"]) end - def test_url_host_memory_db_for_sqlite3 - spec = resolve 'sqlite3://foo:bar@dburl:9000/:memory:' + def test_url_relative_path_for_sqlite3 + spec = resolve 'sqlite3:foo_test' + assert_equal('foo_test', spec["database"]) + end + + def test_url_memory_db_for_sqlite3 + spec = resolve 'sqlite3::memory:' assert_equal(':memory:', spec["database"]) end + + def test_url_sub_key_for_sqlite3 + spec = resolve :production, 'production' => {"url" => 'sqlite3:foo?encoding=utf8'} + assert_equal({ + "adapter" => "sqlite3", + "database" => "foo", + "encoding" => "utf8" }, spec) + end + end end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 1147418815..cf0235b8c5 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -254,7 +254,7 @@ class FixturesTest < ActiveRecord::TestCase def test_fixtures_are_set_up_with_database_env_variable db_url_tmp = ENV['DATABASE_URL'] - ENV['DATABASE_URL'] = "sqlite3:///:memory:" + ENV['DATABASE_URL'] = "sqlite3::memory:" ActiveRecord::Base.stubs(:configurations).returns({}) test_case = Class.new(ActiveRecord::TestCase) do fixtures :accounts diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 460fd3c301..f8f9e9cbd9 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -580,13 +580,13 @@ The only way to explicitly not use the connection information in `ENV['DATABASE_ ``` $ cat config/database.yml development: - url: sqlite3://localhost/NOT_my_database + url: sqlite3:NOT_my_database $ echo $DATABASE_URL postgresql://localhost/my_database $ rails runner 'puts ActiveRecord::Base.connections' -{"development"=>{"adapter"=>"sqlite3", "host"=>"localhost", "database"=>"NOT_my_database"}} +{"development"=>{"adapter"=>"sqlite3", "database"=>"NOT_my_database"}} ``` Here the connection information in `ENV['DATABASE_URL']` is ignored, note the different adapter and database name. diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml index 7312ddb6cd..71934bb48c 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml @@ -23,8 +23,10 @@ test: # Do not keep production credentials in the repository, # instead read the configuration from the environment. # -# Example: -# sqlite3://myuser:mypass@localhost/full/path/to/somedatabase +# Examples: +# sqlite3::memory: +# sqlite3:db/production.sqlite3 +# sqlite3:/full/path/to/database.sqlite3 # production: url: <%%= ENV["DATABASE_URL"] %> diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 3601a58f67..8e76bf27f3 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -216,8 +216,8 @@ module ApplicationTests require "#{app_path}/config/environment" orig_database_url = ENV.delete("DATABASE_URL") orig_rails_env, Rails.env = Rails.env, 'development' - database_url_db_name = File.join(app_path, "db/database_url_db.sqlite3") - ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}" + database_url_db_name = "db/database_url_db.sqlite3" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index b2c52a092f..15414db00f 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -17,11 +17,11 @@ module ApplicationTests end def database_url_db_name - File.join(app_path, "db/database_url_db.sqlite3") + "db/database_url_db.sqlite3" end def set_database_url - ENV['DATABASE_URL'] = File.join("sqlite3://:@localhost", database_url_db_name) + ENV['DATABASE_URL'] = "sqlite3:#{database_url_db_name}" # ensure it's using the DATABASE_URL FileUtils.rm_rf("#{app_path}/config/database.yml") end -- cgit v1.2.3 From 0a99fddc140d8aa54a8922e745624a250877658b Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Thu, 3 Apr 2014 01:41:34 +1030 Subject: Complete change of `sqlite3:///` path handling That which was now relative is now absolute. --- activerecord/CHANGELOG.md | 8 ++++++++ .../connection_adapters/connection_specification.rb | 16 +--------------- .../test/cases/connection_specification/resolver_test.rb | 4 ++-- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 38ac8bdfeb..5cb5fa56b3 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* As promised, switch `sqlite3:///` URLs (which were temporarily + deprecated in 4.1) from relative to absolute. + + If you still want the previous interpretation, you should replace + `sqlite3:///my/path` with `sqlite3:my/path`. + + *Matthew Draper* + * (Temporarily) deprecate SQLite database URLs containing an authority. diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 5ede946836..56c533c401 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -41,7 +41,6 @@ module ActiveRecord else @query = @uri.query end - @authority = url =~ %r{\A[^:]*://} end # Converts the given URL to a full connection hash. @@ -91,21 +90,8 @@ module ActiveRecord end # Returns name of the database. - # Sqlite3's handling of a leading slash is in transition as of - # Rails 4.1. def database_from_path - if @authority && @adapter == 'sqlite3' - # 'sqlite3:///foo' is relative, for backwards compatibility. - - database_name = uri.path.sub(%r{^/}, "") - - msg = "Paths in SQLite3 database URLs of the form `sqlite3:///path` will be treated as absolute in Rails 4.2. " \ - "Please switch to `sqlite3:#{database_name}`." - ActiveSupport::Deprecation.warn(msg) - - database_name - - elsif @adapter == 'sqlite3' + if @adapter == 'sqlite3' # 'sqlite3:/foo' is absolute, because that makes sense. The # corresponding relative version, 'sqlite3:foo', is handled # elsewhere, as an "opaque". diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb index a4fe87049a..3c2f5d4219 100644 --- a/activerecord/test/cases/connection_specification/resolver_test.rb +++ b/activerecord/test/cases/connection_specification/resolver_test.rb @@ -83,8 +83,8 @@ module ActiveRecord end def test_url_with_authority_for_sqlite3 - spec = assert_deprecated { resolve 'sqlite3:///foo_test' } - assert_equal('foo_test', spec["database"]) + spec = resolve 'sqlite3:///foo_test' + assert_equal('/foo_test', spec["database"]) end def test_url_absolute_path_for_sqlite3 -- cgit v1.2.3 From 654dd04af61727e94b293b6713d8775b8d8ad630 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Wed, 2 Apr 2014 13:17:21 -0300 Subject: Move require to actual file Change to require all active_support/deprecation since that's the actual entry point for the deprecation methods. --- activesupport/lib/active_support/core_ext/string/output_safety.rb | 1 + activesupport/test/core_ext/string_ext_test.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 85cc75ff9a..2c8995be9a 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,5 +1,6 @@ require 'erb' require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/deprecation' class ERB module Util diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index d761a0dbd8..ea12f1ced5 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -4,7 +4,6 @@ require 'abstract_unit' require 'inflector_test_cases' require 'constantize_test_cases' -require 'active_support/deprecation/reporting' require 'active_support/inflector' require 'active_support/core_ext/string' require 'active_support/time' -- cgit v1.2.3 From 5aa4157ae44112f61ef923cab33fa1e0aa381e41 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Wed, 2 Apr 2014 13:19:13 -0300 Subject: Fix cookie serializer docs The option actually needs to be set on action_dispatch. [ci skip] --- guides/source/upgrading_ruby_on_rails.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 0045206c76..88c9981dbb 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -104,9 +104,9 @@ Applications created before Rails 4.1 uses `Marshal` to serialize cookie values the signed and encrypted cookie jars. If you want to use the new `JSON`-based format in your application, you can add an initializer file with the following content: - ```ruby - Rails.application.config.cookies_serializer = :hybrid - ``` +```ruby +Rails.application.config.action_dispatch.cookies_serializer = :hybrid +``` This would transparently migrate your existing `Marshal`-serialized cookies into the new `JSON`-based format. -- cgit v1.2.3 From 88e60a48ec7f3447225e9f5e47a251d6e1af78e2 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Thu, 3 Apr 2014 03:33:40 +1030 Subject: Avoid a spurious deprecation warning for database URLs This is all about the case where we have a `DATABASE_URL`, and we have a `database.yml` present, but the latter doesn't contain the key we're looking for. If the key is a symbol, we'll always connect to `DATABASE_URL`, per the new behaviour in 283a2edec2f8ccdf90fb58025608f02a63948fa0. If the key is a string, on the other hand, it should always be a URL: the ability to specify a name not present in `database.yml` is new in this version of Rails, and that ability does not stretch to the deprecated use of a string in place of a symbol. Uncovered by @guilleiguaran while investigating #14495 -- this actually may be related to the original report, but we don't have enough info to confirm. --- .../connection_specification.rb | 50 ++++++++++++---------- .../connection_adapters/connection_handler_test.rb | 48 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 9a133168f8..09ef0f389a 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -124,7 +124,7 @@ module ActiveRecord if config resolve_connection config elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call - resolve_env_connection env.to_sym + resolve_symbol_connection env.to_sym else raise AdapterNotSpecified end @@ -193,40 +193,39 @@ module ActiveRecord # def resolve_connection(spec) case spec - when Symbol, String - resolve_env_connection spec + when Symbol + resolve_symbol_connection spec + when String + resolve_string_connection spec when Hash resolve_hash_connection spec end end + def resolve_string_connection(spec) + # Rails has historically accepted a string to mean either + # an environment key or a URL spec, so we have deprecated + # this ambiguous behaviour and in the future this function + # can be removed in favor of resolve_url_connection. + if configurations.key?(spec) + ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \ + "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead" + resolve_connection(configurations[spec]) + else + resolve_url_connection(spec) + end + end + # Takes the environment such as `:production` or `:development`. # This requires that the @configurations was initialized with a key that # matches. # - # - # Resolver.new("production" => {}).resolve_env_connection(:production) + # Resolver.new("production" => {}).resolve_symbol_connection(:production) # # => {} # - # Takes a connection URL. - # - # Resolver.new({}).resolve_env_connection("postgresql://localhost/foo") - # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } - # - def resolve_env_connection(spec) - # Rails has historically accepted a string to mean either - # an environment key or a URL spec, so we have deprecated - # this ambiguous behaviour and in the future this function - # can be removed in favor of resolve_string_connection and - # resolve_symbol_connection. + def resolve_symbol_connection(spec) if config = configurations[spec.to_s] - if spec.is_a?(String) - ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \ - "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead" - end resolve_connection(config) - elsif spec.is_a?(String) - resolve_string_connection(spec) else raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available configuration: #{configurations.inspect}") end @@ -244,7 +243,12 @@ module ActiveRecord spec end - def resolve_string_connection(url) + # Takes a connection URL. + # + # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo") + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # + def resolve_url_connection(url) ConnectionUrlResolver.new(url).to_hash end end diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index 2992ceb211..e097449029 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -17,6 +17,54 @@ module ActiveRecord ENV["DATABASE_URL"] = @previous_database_url end + def resolve(spec, config) + ConnectionSpecification::Resolver.new(klass.new(config).resolve).resolve(spec) + end + + def spec(spec, config) + ConnectionSpecification::Resolver.new(klass.new(config).resolve).spec(spec) + end + + def test_resolver_with_database_uri_and_known_key + ENV['DATABASE_URL'] = "postgres://localhost/foo" + config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo" } } + actual = resolve(:production, config) + expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + assert_equal expected, actual + end + + def test_resolver_with_database_uri_and_known_string_key + ENV['DATABASE_URL'] = "postgres://localhost/foo" + config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo" } } + actual = assert_deprecated { resolve("production", config) } + expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + assert_equal expected, actual + end + + def test_resolver_with_database_uri_and_unknown_symbol_key + ENV['DATABASE_URL'] = "postgres://localhost/foo" + config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } + actual = resolve(:production, config) + expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + assert_equal expected, actual + end + + def test_resolver_with_database_uri_and_unknown_string_key + ENV['DATABASE_URL'] = "postgres://localhost/foo" + config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } + assert_raises AdapterNotSpecified do + spec("production", config) + end + end + + def test_resolver_with_database_uri_and_supplied_url + ENV['DATABASE_URL'] = "not-postgres://not-localhost/not_foo" + config = { "production" => { "adapter" => "also_not_postgres", "database" => "also_not_foo" } } + actual = resolve("postgres://localhost/foo", config) + expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + assert_equal expected, actual + end + def test_jdbc_url config = { "production" => { "url" => "jdbc:postgres://localhost/foo" } } actual = klass.new(config).resolve -- cgit v1.2.3 From ad1415381e4d6a74ac418b1bf4ba042b1f369765 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Thu, 3 Apr 2014 06:19:18 +1030 Subject: Avoid including DB details in exception messages The keys are quite sufficient; we shouldn't be throwing passwords around. --- .../lib/active_record/connection_adapters/connection_specification.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 09ef0f389a..d60d31eda4 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -227,7 +227,7 @@ module ActiveRecord if config = configurations[spec.to_s] resolve_connection(config) else - raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available configuration: #{configurations.inspect}") + raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}") end end -- cgit v1.2.3 From 1b187caaa1e1aa1bd0f440052b4df09a5ddaa4bf Mon Sep 17 00:00:00 2001 From: Jefferson Lai Date: Tue, 1 Apr 2014 20:18:16 -0700 Subject: CollectionProxy uses the arel of its association's scope. CollectionProxy should be able to reuse the behavior (methods) of its parent class, but with its own state. This change allows CollectionProxy to use the arel object corresponding to its association's scope. --- activerecord/CHANGELOG.md | 9 +++++++++ activerecord/lib/active_record/associations/collection_proxy.rb | 4 ++++ activerecord/test/cases/relations_test.rb | 6 ++++++ activerecord/test/models/post.rb | 4 ++++ 4 files changed, 23 insertions(+) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 1aeba4f856..d31551d606 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,12 @@ +* `to_sql` on an association now matches the query that is actually executed, where it + could previously have incorrectly accrued additional conditions (e.g. as a result of + a previous query). CollectionProxy now always defers to the association scope's + `arel` method so the (incorrect) inherited one should be entirely concealed. + + Fixes #14003. + + *Jefferson Lai* + * The PostgreSQL adapter supports custom domains. Fixes #14305. *Yves Senn* diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index eba688866c..5b71ed163e 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -860,6 +860,10 @@ module ActiveRecord !!@association.include?(record) end + def arel + scope.arel + end + def proxy_association @association end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index fddb7c204a..049c5a0606 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -573,6 +573,12 @@ class RelationTest < ActiveRecord::TestCase assert_equal expected, actual end + def test_to_sql_on_scoped_proxy + auth = Author.first + Post.where("1=1").written_by(auth) + assert_not auth.posts.to_sql.include?("1=1") + end + def test_loading_with_one_association_with_non_preload posts = Post.eager_load(:last_comment).order('comments.id DESC') post = posts.find { |p| p.id == 1 } diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index faf539a562..099e039255 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -149,6 +149,10 @@ class Post < ActiveRecord::Base ranked_by_comments.limit_by(limit) end + def self.written_by(author) + where(id: author.posts.pluck(:id)) + end + def self.reset_log @log = [] end -- cgit v1.2.3 From 3f70c69437531e975838d1788b13570972453113 Mon Sep 17 00:00:00 2001 From: Nikolay Shebanov Date: Wed, 2 Apr 2014 13:12:52 +0400 Subject: Fix default_url_options example in i18n guide [ci skip] --- guides/source/i18n.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/guides/source/i18n.md b/guides/source/i18n.md index bef738b75b..6bd033f0de 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -212,17 +212,16 @@ The most usual way of setting (and passing) the locale would be to include it in This approach has almost the same set of advantages as setting the locale from the domain name: namely that it's RESTful and in accord with the rest of the World Wide Web. It does require a little bit more work to implement, though. -Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL (e.g. `link_to( books_url(locale: I18n.locale))`) would be tedious and probably impossible, of course. +Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL, e.g. `link_to(books_url(locale: I18n.locale))`, would be tedious and probably impossible, of course. -Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000515), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000503) and helper methods dependent on it (by implementing/overriding this method). +Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-default_url_options), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for) and helper methods dependent on it (by implementing/overriding this method). We can include something like this in our `ApplicationController` then: ```ruby # app/controllers/application_controller.rb -def default_url_options(options={}) - logger.debug "default_url_options is passed options: #{options.inspect}\n" - { locale: I18n.locale } +def default_url_options(options = {}) + { locale: I18n.locale }.merge options end ``` -- cgit v1.2.3 From 34a3d425ea78786c63757028257b63b895e60960 Mon Sep 17 00:00:00 2001 From: ariabov Date: Wed, 2 Apr 2014 23:39:22 -0700 Subject: In Active Record Querying guide, currently `Merging of scopes` section uses a concept of default scope in its example before it is introduced in the following section titled `Applying a default scope`. It makes more sense to switch the ordering to introduce default scopes (`Applying a default scope`) first and then go into `Merging of scopes` section where it is used. --- guides/CHANGELOG.md | 4 +++ guides/source/active_record_querying.md | 59 ++++++++++++++++----------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index a7c215c295..246e1d3b96 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1 +1,5 @@ +* Switched the order of `Applying a default scope` and `Merging of scopes` subsections so default scopes are introduced first. + + *Alex Riabov* + Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/guides/CHANGELOG.md) for previous changes. diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 0a332d7dd9..2a76df156c 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1231,6 +1231,35 @@ Using a class method is the preferred way to accept arguments for scopes. These category.posts.created_before(time) ``` +### Applying a default scope + +If we wish for a scope to be applied across all queries to the model we can use the +`default_scope` method within the model itself. + +```ruby +class Client < ActiveRecord::Base + default_scope { where("removed_at IS NULL") } +end +``` + +When queries are executed on this model, the SQL query will now look something like +this: + +```sql +SELECT * FROM clients WHERE removed_at IS NULL +``` + +If you need to do more complex things with a default scope, you can alternatively +define it as a class method: + +```ruby +class Client < ActiveRecord::Base + def self.default_scope + # Should return an ActiveRecord::Relation. + end +end +``` + ### Merging of scopes Just like `where` clauses scopes are merged using `AND` conditions. @@ -1284,36 +1313,6 @@ User.where(state: 'inactive') As you can see above the `default_scope` is being merged in 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 -`default_scope` method within the model itself. - -```ruby -class Client < ActiveRecord::Base - default_scope { where("removed_at IS NULL") } -end -``` - -When queries are executed on this model, the SQL query will now look something like -this: - -```sql -SELECT * FROM clients WHERE removed_at IS NULL -``` - -If you need to do more complex things with a default scope, you can alternatively -define it as a class method: - -```ruby -class Client < ActiveRecord::Base - def self.default_scope - # Should return an ActiveRecord::Relation. - end -end -``` - ### Removing All Scoping If we wish to remove scoping for any reason we can use the `unscoped` method. This is -- cgit v1.2.3 From f1169d9d2509189a16f7b03fee5c76b9d023a347 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 1 Apr 2014 22:04:10 -0700 Subject: Add ConnectionHelper to refactor tests. --- .../test/cases/adapters/mysql/active_schema_test.rb | 9 ++++----- .../test/cases/adapters/mysql/connection_test.rb | 11 ++--------- .../test/cases/adapters/mysql2/active_schema_test.rb | 9 ++++----- .../test/cases/adapters/mysql2/connection_test.rb | 14 +++----------- .../test/cases/adapters/postgresql/connection_test.rb | 15 +++------------ .../test/cases/adapters/postgresql/domain_test.rb | 6 +++--- activerecord/test/cases/adapters/postgresql/enum_test.rb | 6 +++--- .../test/cases/adapters/postgresql/range_test.rb | 16 ++++++++-------- activerecord/test/support/connection_helper.rb | 14 ++++++++++++++ activerecord/test/support/postgresql_helper.rb | 8 -------- 10 files changed, 44 insertions(+), 64 deletions(-) create mode 100644 activerecord/test/support/connection_helper.rb delete mode 100644 activerecord/test/support/postgresql_helper.rb diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index d1c644c016..7c0f11b033 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -1,10 +1,10 @@ require "cases/helper" +require 'support/connection_helper' class ActiveSchemaTest < ActiveRecord::TestCase - def setup - @connection = ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(@connection) + include ConnectionHelper + def setup ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute def execute(sql, name = nil) return sql end @@ -12,8 +12,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase end teardown do - ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(@connection) + reset_connection end def test_add_index diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 42ffb91095..412efa22ff 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -1,7 +1,9 @@ require "cases/helper" +require 'support/connection_helper' require 'support/ddl_helper' class MysqlConnectionTest < ActiveRecord::TestCase + include ConnectionHelper include DdlHelper class Klass < ActiveRecord::Base @@ -160,15 +162,6 @@ class MysqlConnectionTest < ActiveRecord::TestCase private - def run_without_connection - original_connection = ActiveRecord::Base.remove_connection - begin - yield original_connection - ensure - ActiveRecord::Base.establish_connection(original_connection) - end - end - def with_example_table(&block) definition ||= <<-SQL `id` int(11) auto_increment PRIMARY KEY, diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 81c614924f..cefc3e3c7e 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -1,10 +1,10 @@ require "cases/helper" +require 'support/connection_helper' class ActiveSchemaTest < ActiveRecord::TestCase - def setup - @connection = ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(@connection) + include ConnectionHelper + def setup ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute def execute(sql, name = nil) return sql end @@ -12,8 +12,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase end teardown do - ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(@connection) + reset_connection end def test_add_index diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index 57d8b8dd99..182d9409c7 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -1,6 +1,9 @@ require "cases/helper" +require 'support/connection_helper' class MysqlConnectionTest < ActiveRecord::TestCase + include ConnectionHelper + def setup super @subscriber = SQLSubscriber.new @@ -103,15 +106,4 @@ class MysqlConnectionTest < ActiveRecord::TestCase assert_equal "'1970-01-01 00:00:00.000000'", @connection.quote(Time.at(0).to_datetime) end end - - private - - def run_without_connection - original_connection = ActiveRecord::Base.remove_connection - begin - yield original_connection - ensure - ActiveRecord::Base.establish_connection(original_connection) - end - end end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index 514ae20e3c..5f84c893c0 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -1,7 +1,10 @@ require "cases/helper" +require 'support/connection_helper' module ActiveRecord class PostgresqlConnectionTest < ActiveRecord::TestCase + include ConnectionHelper + class NonExistentTable < ActiveRecord::Base end @@ -198,17 +201,5 @@ module ActiveRecord ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:debug_print_plan => :default}})) end end - - private - - def run_without_connection - original_connection = ActiveRecord::Base.remove_connection - begin - yield original_connection - ensure - ActiveRecord::Base.establish_connection(original_connection) - end - end - end end diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb index ba25a64fac..214e89dd7f 100644 --- a/activerecord/test/cases/adapters/postgresql/domain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- require "cases/helper" -require 'support/postgresql_helper' +require 'support/connection_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlDomainTest < ActiveRecord::TestCase - include PostgresqlHelper + include ConnectionHelper class PostgresqlDomain < ActiveRecord::Base self.table_name = "postgresql_domains" @@ -27,7 +27,7 @@ class PostgresqlDomainTest < ActiveRecord::TestCase teardown do @connection.execute 'DROP TABLE IF EXISTS postgresql_domains' @connection.execute 'DROP DOMAIN IF EXISTS custom_money' - reset_pg_session + reset_connection end def test_column diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index fde01314a5..73da5a74ab 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- require "cases/helper" -require 'support/postgresql_helper' +require 'support/connection_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlEnumTest < ActiveRecord::TestCase - include PostgresqlHelper + include ConnectionHelper class PostgresqlEnum < ActiveRecord::Base self.table_name = "postgresql_enums" @@ -28,7 +28,7 @@ class PostgresqlEnumTest < ActiveRecord::TestCase teardown do @connection.execute 'DROP TABLE IF EXISTS postgresql_enums' @connection.execute 'DROP TYPE IF EXISTS mood' - reset_pg_session + reset_connection end def test_column diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index b57568dbad..57c7da2657 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/postgresql_helper' +require 'support/connection_helper' require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' @@ -10,13 +10,7 @@ if ActiveRecord::Base.connection.supports_ranges? class PostgresqlRangeTest < ActiveRecord::TestCase self.use_transactional_fixtures = false - include PostgresqlHelper - - teardown do - @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges' - @connection.execute 'DROP TYPE IF EXISTS floatrange' - reset_pg_session - end + include ConnectionHelper def setup @connection = PostgresqlRange.connection @@ -99,6 +93,12 @@ _SQL @empty_range = PostgresqlRange.find(105) end + teardown do + @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges' + @connection.execute 'DROP TYPE IF EXISTS floatrange' + reset_connection + end + def test_data_type_of_range_types assert_equal :daterange, @first_range.column_for_attribute(:date_range).type assert_equal :numrange, @first_range.column_for_attribute(:num_range).type diff --git a/activerecord/test/support/connection_helper.rb b/activerecord/test/support/connection_helper.rb new file mode 100644 index 0000000000..4a19e5df44 --- /dev/null +++ b/activerecord/test/support/connection_helper.rb @@ -0,0 +1,14 @@ +module ConnectionHelper + def run_without_connection + original_connection = ActiveRecord::Base.remove_connection + yield original_connection + ensure + ActiveRecord::Base.establish_connection(original_connection) + end + + # Used to drop all cache query plans in tests. + def reset_connection + original_connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(original_connection) + end +end diff --git a/activerecord/test/support/postgresql_helper.rb b/activerecord/test/support/postgresql_helper.rb deleted file mode 100644 index fa40a46499..0000000000 --- a/activerecord/test/support/postgresql_helper.rb +++ /dev/null @@ -1,8 +0,0 @@ -module PostgresqlHelper - # Make sure to drop all cached query plans to prevent invalid reference errors like: - # cache lookup failed for type XYZ - def reset_pg_session - original_connection = ActiveRecord::Base.remove_connection - ActiveRecord::Base.establish_connection(original_connection) - end -end -- cgit v1.2.3 From 1f432c54658cf54608a6e37b70b8dc8e40521502 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrov Date: Thu, 27 Mar 2014 15:29:20 +0300 Subject: Treat blank UUID values as nil --- activerecord/CHANGELOG.md | 8 ++++++++ .../lib/active_record/connection_adapters/postgresql/oid.rb | 9 ++++++++- activerecord/test/cases/adapters/postgresql/uuid_test.rb | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index acd3d395c5..f7718394af 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* Treat blank UUID values as `nil`. + + Example: + + Sample.new(uuid_field: '') #=> + + *Dmitry Lavrov* + * Enable support for materialized views on PostgreSQL >= 9.3. *Dave Lee* diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 57bdc3bb19..9e898015a6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -330,6 +330,13 @@ This is not reliable and will be removed in the future. end end + class Uuid < Type + def type; :uuid end + def type_cast(value) + value.presence + end + end + class TypeMap def initialize @mapping = {} @@ -418,10 +425,10 @@ This is not reliable and will be removed in the future. register_type 'json', OID::Json.new register_type 'cidr', OID::Cidr.new register_type 'inet', OID::Inet.new + register_type 'uuid', OID::Uuid.new register_type 'xml', SpecializedString.new(:xml) register_type 'tsvector', SpecializedString.new(:tsvector) register_type 'macaddr', SpecializedString.new(:macaddr) - register_type 'uuid', SpecializedString.new(:uuid) register_type 'citext', SpecializedString.new(:citext) register_type 'ltree', SpecializedString.new(:ltree) diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index f79a7a598b..9e03ea6bee 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -50,6 +50,11 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase assert_not column.array end + def test_treat_blank_uuid_as_nil + UUIDType.create! guid: '' + assert_equal(nil, UUIDType.last.guid) + end + def test_uuid_formats ["A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11", "{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}", -- cgit v1.2.3 From db5d26c9d70fb72b8aa3ea98709224dd13800024 Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Wed, 2 Apr 2014 19:27:55 -0300 Subject: Fix error when using `with_options` with lambda. It was causing error when using `with_options` passing a lambda as its last argument. class User < ActiveRecord::Base with_options dependent: :destroy do |assoc| assoc.has_many :profiles, -> { where(active: true) } end end It was happening because the `option_merger` was taking the last argument and checking if it was a Hash. This breaks the HasMany usage, because its last argument can be a Hash or a Proc. As the behavior described in this test: https://github.com/rails/rails/blob/master/activesupport/test/option_merger_test.rb#L69 the method will only accept the lambda, this way it will keep the expected behavior. See 9eaa0a34 --- activerecord/CHANGELOG.md | 6 ++++++ .../test/cases/associations/has_many_associations_test.rb | 9 +++++++++ activerecord/test/models/college.rb | 5 +++++ activerecord/test/models/student.rb | 1 + activerecord/test/schema/schema.rb | 2 ++ activesupport/lib/active_support/option_merger.rb | 2 +- 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index f7718394af..186bff580a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Fixed error when using `with_options` with lambda. + + Fixes #9805. + + *Lauro Caetano* + * Treat blank UUID values as `nil`. Example: diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 3dfb0a27ba..eb0ebc75ad 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -24,6 +24,8 @@ require 'models/minivan' require 'models/speedometer' require 'models/reference' require 'models/job' +require 'models/college' +require 'models/student' class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase fixtures :authors, :posts, :comments @@ -65,6 +67,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase dev.developer_projects.map(&:project_id).sort end + def test_has_many_build_with_options + college = College.create(name: 'UFMT') + student = Student.create(active: true, college_id: college.id, name: 'Sarah') + + assert_equal college.students, Student.where(active: true, college_id: college.id) + end + def test_create_from_association_should_respect_default_scope car = Car.create(:name => 'honda') assert_equal 'honda', car.name diff --git a/activerecord/test/models/college.rb b/activerecord/test/models/college.rb index c7495d7deb..501af4a8dd 100644 --- a/activerecord/test/models/college.rb +++ b/activerecord/test/models/college.rb @@ -1,5 +1,10 @@ require_dependency 'models/arunit2_model' +require 'active_support/core_ext/object/with_options' class College < ARUnit2Model has_many :courses + + with_options dependent: :destroy do |assoc| + assoc.has_many :students, -> { where(active: true) } + end end diff --git a/activerecord/test/models/student.rb b/activerecord/test/models/student.rb index f459f2a9a3..28a0b6c99b 100644 --- a/activerecord/test/models/student.rb +++ b/activerecord/test/models/student.rb @@ -1,3 +1,4 @@ class Student < ActiveRecord::Base has_and_belongs_to_many :lessons + belongs_to :college end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index b44e72a67c..a9c4980283 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -638,6 +638,8 @@ ActiveRecord::Schema.define do create_table :students, force: true do |t| t.string :name + t.boolean :active + t.integer :college_id end create_table :subscribers, force: true, id: false do |t| diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index e55ffd12c3..dea84e437f 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -12,7 +12,7 @@ module ActiveSupport private def method_missing(method, *arguments, &block) - if arguments.last.is_a?(Proc) + if arguments.first.is_a?(Proc) proc = arguments.pop arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) } else -- cgit v1.2.3 From 272f7c29e2105f33a6f4131cfaf423bfd05b6040 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Fri, 4 Apr 2014 04:29:50 +1030 Subject: Explicitly load Kernel#y when starting a console Previously, we relied on the IRB-detection in Psych itself. But that doesn't work when we're running under spring: the application boots (and thus psych is required) before we switch to console mode and load IRB. Fixes #14587. --- railties/lib/rails/engine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 5661094d95..c38cc3b5e5 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -430,6 +430,7 @@ module Rails # Check Rails::Railtie.console for more info. def load_console(app=self) require "pp" + require "psych/y" require "rails/console/app" require "rails/console/helpers" run_console_blocks(app) -- cgit v1.2.3 From 251840f20adca3b727a3c3a659a5ce9db47ff260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Adamczak?= Date: Thu, 3 Apr 2014 20:05:51 +0200 Subject: Improve error message for guides:generate:kindle With `kindlegen` missing from the PATH, the task keeps suggesting to `gem install kindlerb`. This change provides a more meaningful error message for guides:generate:kindle. --- guides/Rakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/Rakefile b/guides/Rakefile index d6dd950d01..94d4be8c0a 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -13,8 +13,8 @@ namespace :guides do desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/kindlepublishing" task :kindle do - unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/ - abort "Please `gem install kindlerb`" + unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/ + abort "Please `gem install kindlerb` and make sure you have `kindlegen` in your PATH" end unless `convert` =~ /convert/ abort "Please install ImageMagick`" -- cgit v1.2.3 From 815c9deae8de557688e1c99aabe30454bcbe5970 Mon Sep 17 00:00:00 2001 From: Arthur Neves Date: Thu, 3 Apr 2014 10:39:05 -0400 Subject: Block a few default Class methods as scope name. Add tests to make sure scopes cannot be create with names such as: private, protected, public. Make sure enum values don't collide with those methods too. --- activerecord/CHANGELOG.md | 8 ++++++++ activerecord/lib/active_record/attribute_methods.rb | 4 +++- activerecord/test/cases/enum_test.rb | 1 + activerecord/test/cases/scoping/named_scoping_test.rb | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 4abfdfa81b..98fe0fbd62 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* Block a few default Class methods as scope name. + + For instance, this will raise: + + scope :public, -> { where(status: 1) } + + *arthurnn* + * Fixed error when using `with_options` with lambda. Fixes #9805. diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index ea48a13ea8..4b1733619a 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -29,6 +29,8 @@ module ActiveRecord end } + BLACKLISTED_CLASS_METHODS = %w(private public protected) + class AttributeMethodCache def initialize @module = Module.new @@ -132,7 +134,7 @@ module ActiveRecord # A class method is 'dangerous' if it is already (re)defined by Active Record, but # not by any ancestors. (So 'puts' is not dangerous but 'new' is.) def dangerous_class_method?(method_name) - class_method_defined_within?(method_name, Base) + BLACKLISTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base) end def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index f8ebd7caee..47de3dec98 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -194,6 +194,7 @@ class EnumTest < ActiveRecord::TestCase :valid, # generates #valid?, which conflicts with an AR method :save, # generates #save!, which conflicts with an AR method :proposed, # same value as an existing enum + :public, :private, :protected, # generates a method that conflict with ruby words ] conflicts.each_with_index do |value, i| diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb index f0ad9ebb8a..59ec2dd6a4 100644 --- a/activerecord/test/cases/scoping/named_scoping_test.rb +++ b/activerecord/test/cases/scoping/named_scoping_test.rb @@ -291,6 +291,9 @@ class NamedScopingTest < ActiveRecord::TestCase :relation, # private class method on AR::Base :new, # redefined class method on AR::Base :all, # a default scope + :public, + :protected, + :private ] non_conflicts = [ -- cgit v1.2.3 From 20181e4fa94c50c8afe02181a5537e93caafcd2c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 3 Apr 2014 18:56:51 -0700 Subject: Prevent state leak in test. This will allow us to run the tests in random order. --- .../test/cases/adapters/postgresql/schema_test.rb | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 5e5f653d17..11ec7599a3 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -271,13 +271,13 @@ class SchemaTest < ActiveRecord::TestCase end def test_with_uppercase_index_name - ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" - assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"} + @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" + assert_nothing_raised { @connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"} + @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" - ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" - ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME - assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "things_Index"} - ActiveRecord::Base.connection.schema_search_path = "public" + with_schema_search_path SCHEMA_NAME do + assert_nothing_raised { @connection.remove_index! "things", "things_Index"} + end end def test_primary_key_with_schema_specified @@ -328,18 +328,17 @@ class SchemaTest < ActiveRecord::TestCase end def test_prepared_statements_with_multiple_schemas + [SCHEMA_NAME, SCHEMA2_NAME].each do |schema_name| + with_schema_search_path schema_name do + Thing5.create(:id => 1, :name => "thing inside #{SCHEMA_NAME}", :email => "thing1@localhost", :moment => Time.now) + end + end - @connection.schema_search_path = SCHEMA_NAME - Thing5.create(:id => 1, :name => "thing inside #{SCHEMA_NAME}", :email => "thing1@localhost", :moment => Time.now) - - @connection.schema_search_path = SCHEMA2_NAME - Thing5.create(:id => 1, :name => "thing inside #{SCHEMA2_NAME}", :email => "thing1@localhost", :moment => Time.now) - - @connection.schema_search_path = SCHEMA_NAME - assert_equal 1, Thing5.count - - @connection.schema_search_path = SCHEMA2_NAME - assert_equal 1, Thing5.count + [SCHEMA_NAME, SCHEMA2_NAME].each do |schema_name| + with_schema_search_path schema_name do + assert_equal 1, Thing5.count + end + end end def test_schema_exists? -- cgit v1.2.3 From f4226c3ab6651f6871e02f3c6754c29ab155b938 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Thu, 3 Apr 2014 14:59:53 +0200 Subject: PostgreSQL and SQLite, remove varchar limit. [Vladimir Sazhin & Toms Mikoss & Yves Senn] There is no reason for the PG adapter to have a default limit of 255 on :string columns. See this snippet from the PG docs: Tip: There is no performance difference among these three types, apart from increased storage space when using the blank-padded type, and a few extra CPU cycles to check the length when storing into a length-constrained column. While character(n) has performance advantages in some other database systems, there is no such advantage in PostgreSQL; in fact character(n) is usually the slowest of the three because of its additional storage costs. In most situations text or character varying should be used instead. --- activerecord/CHANGELOG.md | 6 ++++++ .../lib/active_record/connection_adapters/postgresql_adapter.rb | 2 +- .../lib/active_record/connection_adapters/sqlite3_adapter.rb | 2 +- activerecord/test/cases/adapters/postgresql/array_test.rb | 2 +- activerecord/test/cases/reflection_test.rb | 2 +- activerecord/test/schema/schema.rb | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 98fe0fbd62..dce2692b0d 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* PostgreSQL and SQLite string columns no longer have a default limit of 255. + + Fixes #13435, #9153. + + *Vladimir Sazhin*, *Toms Mikoss*, *Yves Senn* + * Block a few default Class methods as scope name. For instance, this will raise: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 9fe8e0497e..3510e4f3b0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -209,7 +209,7 @@ module ActiveRecord NATIVE_DATABASE_TYPES = { primary_key: "serial primary key", - string: { name: "character varying", limit: 255 }, + string: { name: "character varying" }, text: { name: "text" }, integer: { name: "integer" }, float: { name: "float" }, diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 6e6a51dab8..cd1f7a16c6 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -63,7 +63,7 @@ module ActiveRecord NATIVE_DATABASE_TYPES = { primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', - string: { name: "varchar", limit: 255 }, + string: { name: "varchar" }, text: { name: "text" }, integer: { name: "integer" }, float: { name: "float" }, diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 36ded66998..18dd4a6de8 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -25,7 +25,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase def test_column assert_equal :string, @column.type - assert_equal "character varying(255)", @column.sql_type + assert_equal "character varying", @column.sql_type assert @column.array assert_not @column.text? assert_not @column.number? diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index d7ad5ed29f..ad77472333 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -63,7 +63,7 @@ class ReflectionTest < ActiveRecord::TestCase def test_column_string_type_and_limit assert_equal :string, @first.column_for_attribute("title").type - assert_equal 255, @first.column_for_attribute("title").limit + assert_equal 250, @first.column_for_attribute("title").limit end def test_column_null_not_null diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index a9c4980283..d79cce8cca 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -673,7 +673,7 @@ ActiveRecord::Schema.define do end create_table :topics, force: true do |t| - t.string :title + t.string :title, limit: 250 t.string :author_name t.string :author_email_address if mysql_56? -- cgit v1.2.3 From 80f4a65bbd2372c01cfdf174e6446cd232d81e44 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Fri, 4 Apr 2014 09:16:02 +0200 Subject: test, show current adapter behavior for `add_column limit: nil`. This is an illustration of https://github.com/rails/rails/pull/13435#issuecomment-33789752 Removing the limit from the PG and SQLite adapter solves the issue. MySQL is still affected by the issue. --- activerecord/test/cases/migration/column_attributes_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index ccf19fb4d0..6a02873cba 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -35,6 +35,14 @@ module ActiveRecord assert_no_column TestModel, :last_name end + def test_add_column_without_limit + # TODO: limit: nil should work with all adapters. + skip "MySQL wrongly enforces a limit of 255" if current_adapter?(:MysqlAdapter, :Mysql2Adapter) + add_column :test_models, :description, :string, limit: nil + TestModel.reset_column_information + assert_nil TestModel.columns_hash["description"].limit + end + if current_adapter?(:MysqlAdapter, :Mysql2Adapter) def test_unabstracted_database_dependent_types add_column :test_models, :intelligence_quotient, :tinyint -- cgit v1.2.3 From b058897da8d4421cc10c278f7bfab0e53463a078 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Fri, 4 Apr 2014 22:35:29 +1030 Subject: Ensure we supply Kernel#y for 1.9 too In 1.9, it doesn't live in its own file, so we'll have to define it ourselves. Check RUBY_VERSION, instead of rescuing the require, because we want this to break if `psych/y` moves in a future Ruby release. --- railties/lib/rails/application.rb | 19 +++++++++++++++++++ railties/lib/rails/engine.rb | 2 -- railties/lib/rails/railtie.rb | 18 ++++++++++-------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index e37347b576..dd650e9631 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -332,6 +332,25 @@ module Rails config.helpers_paths end + console do + require "pp" + end + + console do + unless ::Kernel.private_method_defined?(:y) + if RUBY_VERSION >= '2.0' + require "psych/y" + else + module ::Kernel + def y(*objects) + puts ::Psych.dump_stream(*objects) + end + private :y + end + end + end + end + protected alias :build_middleware_stack :app diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index c38cc3b5e5..b36ab3d0d5 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -429,8 +429,6 @@ module Rails # Load console and invoke the registered hooks. # Check Rails::Railtie.console for more info. def load_console(app=self) - require "pp" - require "psych/y" require "rails/console/app" require "rails/console/helpers" run_console_blocks(app) diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8d7e804bdc..2b33beaa2b 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -221,26 +221,28 @@ module Rails protected def run_console_blocks(app) #:nodoc: - self.class.console.each { |block| block.call(app) } + each_registered_block(:console) { |block| block.call(app) } end def run_generators_blocks(app) #:nodoc: - self.class.generators.each { |block| block.call(app) } + each_registered_block(:generators) { |block| block.call(app) } end def run_runner_blocks(app) #:nodoc: - self.class.runner.each { |block| block.call(app) } + each_registered_block(:runner) { |block| block.call(app) } end def run_tasks_blocks(app) #:nodoc: extend Rake::DSL - self.class.rake_tasks.each { |block| instance_exec(app, &block) } + each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) } + end - # Load also tasks from all superclasses - klass = self.class.superclass + private - while klass.respond_to?(:rake_tasks) - klass.rake_tasks.each { |t| instance_exec(app, &t) } + def each_registered_block(type, &block) + klass = self.class + while klass.respond_to?(type) + klass.public_send(type).each(&block) klass = klass.superclass end end -- cgit v1.2.3 From 996658e65551f575571a98f8b6a10bd2da07a90f Mon Sep 17 00:00:00 2001 From: Rajarshi Das Date: Fri, 4 Apr 2014 20:16:26 +0530 Subject: Active support instead of ActiveSupport::Deprecation.silence we can use assert_deprecated --- activesupport/test/core_ext/class/delegating_attributes_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb index 86193c2b07..447b1d10ad 100644 --- a/activesupport/test/core_ext/class/delegating_attributes_test.rb +++ b/activesupport/test/core_ext/class/delegating_attributes_test.rb @@ -33,7 +33,7 @@ class DelegatingAttributesTest < ActiveSupport::TestCase end def test_simple_accessor_declaration - ActiveSupport::Deprecation.silence do + assert_deprecated do single_class.superclass_delegating_accessor :both end @@ -48,7 +48,7 @@ class DelegatingAttributesTest < ActiveSupport::TestCase def test_simple_accessor_declaration_with_instance_reader_false _instance_methods = single_class.public_instance_methods - ActiveSupport::Deprecation.silence do + assert_deprecated do single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false end @@ -60,7 +60,7 @@ class DelegatingAttributesTest < ActiveSupport::TestCase end def test_working_with_simple_attributes - ActiveSupport::Deprecation.silence do + assert_deprecated do single_class.superclass_delegating_accessor :both end @@ -79,7 +79,7 @@ class DelegatingAttributesTest < ActiveSupport::TestCase def test_child_class_delegates_to_parent_but_can_be_overridden parent = Class.new - ActiveSupport::Deprecation.silence do + assert_deprecated do parent.superclass_delegating_accessor :both end -- cgit v1.2.3 From b9774a594339d5ac92503d91d180d88ec1faf436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 09:52:43 -0500 Subject: Remove unused variable --- activerecord/test/cases/associations/has_many_associations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index eb0ebc75ad..c79c0c87c5 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -69,7 +69,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_has_many_build_with_options college = College.create(name: 'UFMT') - student = Student.create(active: true, college_id: college.id, name: 'Sarah') + Student.create(active: true, college_id: college.id, name: 'Sarah') assert_equal college.students, Student.where(active: true, college_id: college.id) end -- cgit v1.2.3 From e412ccbb563ea4abec6b4034094605e1565f56cc Mon Sep 17 00:00:00 2001 From: Steve Agalloco Date: Fri, 4 Apr 2014 11:19:39 -0400 Subject: add missing parentheses to validates_with documentation [skip ci] --- activemodel/lib/active_model/validations/with.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 7022f9bee5..ff41572105 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -53,7 +53,7 @@ module ActiveModel # # Configuration options: # * :on - Specifies when this validation is active - # (:create or :update. + # (:create or :update). # * :if - Specifies a method, proc or string to call to determine # if the validation should occur (e.g. if: :allow_validation, # or if: Proc.new { |user| user.signup_step > 2 }). -- cgit v1.2.3 From a338b39f758216038e9249a6ca47b21c91fe0093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 16:25:46 -0300 Subject: Make possible to use sprockets-rails 2.1 --- Gemfile | 1 + rails.gemspec | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 4a891bf6b5..5bc810fa79 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'rack-cache', '~> 1.2' gem 'jquery-rails', '~> 3.1.0' gem 'turbolinks' gem 'coffee-rails', '~> 4.0.0' +gem 'sprockets-rails', github: 'rails/sprockets-rails' # require: false so bcrypt is loaded only when has_secure_password is used. # This is to avoid ActiveModel (and by extension the entire framework) diff --git a/rails.gemspec b/rails.gemspec index d1c199a97a..4800df0df4 100644 --- a/rails.gemspec +++ b/rails.gemspec @@ -27,5 +27,5 @@ Gem::Specification.new do |s| s.add_dependency 'railties', version s.add_dependency 'bundler', '>= 1.3.0', '< 2.0' - s.add_dependency 'sprockets-rails', '~> 2.0.0' + s.add_dependency 'sprockets-rails', '~> 2.1' end -- cgit v1.2.3 From 61a8fd5e1b23fc0a0630cd1831abdda0bedd1c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 18:03:00 -0300 Subject: Use sass-rails 4.0.3 --- railties/lib/rails/generators/app_base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 2fb49479fe..c066f748ee 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -249,7 +249,7 @@ module Rails 'Use SCSS for stylesheets') else gems << GemfileEntry.version('sass-rails', - '~> 4.0.2', + '~> 4.0.3', 'Use SCSS for stylesheets') end -- cgit v1.2.3 From bc6a94902097b68482479acb49bdd03ba292a3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 18:03:14 -0300 Subject: Declare the assets dependency --- railties/test/application/assets_test.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index b235b51d90..6cc17ad176 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -42,7 +42,7 @@ module ApplicationTests test "assets routes have higher priority" do app_file "app/assets/images/rails.png", "notactuallyapng" - app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;" + app_file "app/assets/javascripts/demo.js.erb", "//= depend_on_asset 'rails.png'\na = <%= image_path('rails.png').inspect %>;" app_file 'config/routes.rb', <<-RUBY Rails.application.routes.draw do @@ -199,7 +199,8 @@ module ApplicationTests end test "precompile creates a manifest file with all the assets listed" do - app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + app_file "app/assets/images/rails.png", "notactuallyapng" + app_file "app/assets/stylesheets/application.css.erb", "//= depend_on_asset 'rails.png'\n <%= asset_path('rails.png') %>" app_file "app/assets/javascripts/application.js", "alert();" # digest is default in false, we must enable it for test environment add_to_config "config.assets.digest = true" @@ -279,7 +280,7 @@ module ApplicationTests test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do app_file "app/assets/images/rails.png", "notactuallyapng" - app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + app_file "app/assets/stylesheets/application.css.erb", "//= depend_on_asset 'rails.png'\n<%= asset_path('rails.png') %>" add_to_config "config.assets.compile = true" add_to_config "config.assets.digest = true" @@ -448,23 +449,23 @@ module ApplicationTests test "asset urls should be protocol-relative if no request is in scope" do app_file "app/assets/images/rails.png", "notreallyapng" - app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";' + app_file "app/assets/javascripts/image_loader.js.erb", "//= depend_on_asset 'rails.png'\n\nvar src='<%= image_path('rails.png') %>';" add_to_config "config.assets.precompile = %w{image_loader.js}" add_to_config "config.asset_host = 'example.com'" precompile! - assert_match 'src="//example.com/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) + assert_match "src='//example.com/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) end test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri" app_file "app/assets/images/rails.png", "notreallyapng" - app_file "app/assets/javascripts/app.js.erb", 'var src="<%= image_path("rails.png") %>";' + app_file "app/assets/javascripts/app.js.erb", "//= depend_on_asset 'rails.png'\n\nvar src='<%= image_path('rails.png') %>';" add_to_config "config.assets.precompile = %w{app.js}" precompile! - assert_match 'src="/sub/uri/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/app-*.js"].first) + assert_match "src='/sub/uri/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/app-*.js"].first) end test "assets:cache:clean should clean cache" do -- cgit v1.2.3 From 989cccdc3e6f9c6dcb740b2792fcc74b19eed67e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 18:41:43 -0300 Subject: Add CHANGELOG entry for #11650 [ci skip] --- activerecord/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fff66f21fb..4d555bd33e 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Make possible to have an association called `records`. + + Fixes #11645. + + *prathamesh-sonpatki* + * `to_sql` on an association now matches the query that is actually executed, where it could previously have incorrectly accrued additional conditions (e.g. as a result of a previous query). CollectionProxy now always defers to the association scope's -- cgit v1.2.3 From 57c7d5cb80086e66eee3303b11a5e558aa9e5bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 19:44:17 -0300 Subject: Fix the test defining the models in the right place --- .../associations/belongs_to_associations_test.rb | 20 +++++--------------- activerecord/test/models/column.rb | 3 +++ activerecord/test/models/record.rb | 2 ++ activerecord/test/schema/schema.rb | 6 ++++++ 4 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 activerecord/test/models/column.rb create mode 100644 activerecord/test/models/record.rb diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 091c94676e..27f6fa575d 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -16,6 +16,8 @@ require 'models/essay' require 'models/toy' require 'models/invoice' require 'models/line_item' +require 'models/column' +require 'models/record' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -886,21 +888,9 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end end - test 'belongs_to works with model name Record' do - Record = Class.new(ActiveRecord::Base) do - connection.create_table :records - end - - Foo = Class.new(ActiveRecord::Base) do - connection.create_table :foos do |t| - t.belongs_to :record - end - - belongs_to :record - end - + test 'belongs_to works with model called Record' do record = Record.create! - Foo.create! record: record - assert_equal 1, Foo.count + Column.create! record: record + assert_equal 1, Column.count end end diff --git a/activerecord/test/models/column.rb b/activerecord/test/models/column.rb new file mode 100644 index 0000000000..499358b4cf --- /dev/null +++ b/activerecord/test/models/column.rb @@ -0,0 +1,3 @@ +class Column < ActiveRecord::Base + belongs_to :record +end diff --git a/activerecord/test/models/record.rb b/activerecord/test/models/record.rb new file mode 100644 index 0000000000..f77ac9fc03 --- /dev/null +++ b/activerecord/test/models/record.rb @@ -0,0 +1,2 @@ +class Record < ActiveRecord::Base +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index a9c4980283..5bd3a51a84 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -161,6 +161,10 @@ ActiveRecord::Schema.define do t.integer :references, null: false end + create_table :columns, force: true do |t| + t.references :record + end + create_table :comments, force: true do |t| t.integer :post_id, null: false # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in @@ -819,6 +823,8 @@ ActiveRecord::Schema.define do t.integer :department_id end + create_table :records, force: true do |t| + end except 'SQLite' do # fk_test_has_fk should be before fk_test_has_pk -- cgit v1.2.3 From f79881e2ad412b415cbf785ae505763e829687e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 4 Apr 2014 19:47:40 -0300 Subject: sprockets-rails was released --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 5bc810fa79..4a891bf6b5 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,6 @@ gem 'rack-cache', '~> 1.2' gem 'jquery-rails', '~> 3.1.0' gem 'turbolinks' gem 'coffee-rails', '~> 4.0.0' -gem 'sprockets-rails', github: 'rails/sprockets-rails' # require: false so bcrypt is loaded only when has_secure_password is used. # This is to avoid ActiveModel (and by extension the entire framework) -- cgit v1.2.3 From 3779c1d45e89d798f53b71f98ba3e6030c0d08a7 Mon Sep 17 00:00:00 2001 From: Andy Callaghan Date: Sat, 5 Apr 2014 17:01:59 +0100 Subject: W3C CSP document moved to gihub.io URL [ci skip] The old link https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html is now being soft redirected to this new URL --- guides/source/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/security.md b/guides/source/security.md index a40c99cbfd..9603fb4a4d 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -1003,7 +1003,7 @@ _'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS at * X-Content-Type-Options _'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file. * X-Content-Security-Policy -[A powerful mechanism for controlling which sites certain content types can be loaded from](http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html) +[A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html) * Access-Control-Allow-Origin Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. * Strict-Transport-Security -- cgit v1.2.3 From 752e7a11be160dd12dfb6a2f00113ce5a9e5256d Mon Sep 17 00:00:00 2001 From: Dmitry Mazuro Date: Sun, 6 Apr 2014 20:39:28 +0300 Subject: Use SVG version of travis build status badge [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f079536d2..c3577efe53 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ We encourage you to contribute to Ruby on Rails! Please check out the ## Code Status -* [![Build Status](https://travis-ci.org/rails/rails.png?branch=master)](https://travis-ci.org/rails/rails) +* [![Build Status](https://travis-ci.org/rails/rails.svg?branch=master)](https://travis-ci.org/rails/rails) ## License -- cgit v1.2.3 From 8bbaa94c8125cf3efc0ec05cee5bf3193fbf5cf7 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Sat, 5 Apr 2014 11:02:18 -0700 Subject: Fix setup of adding _flash_types test. Adding flash types to a controller within any of the tests will result in a global state change of the controller under test. This patch will prevent state leaks and allow us to run the test in random order. --- actionpack/test/controller/flash_test.rb | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 25a4857eba..ff5587d768 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -210,20 +210,29 @@ class FlashTest < ActionController::TestCase end def test_redirect_to_with_adding_flash_types - @controller.class.add_flash_types :foo + original_controller = @controller + test_controller_with_flash_type_foo = Class.new(TestController) do + add_flash_types :foo + end + @controller = test_controller_with_flash_type_foo.new get :redirect_with_foo_flash assert_equal "for great justice", @controller.send(:flash)[:foo] + ensure + @controller = original_controller end - class SubclassesTestController < TestController; end - def test_add_flash_type_to_subclasses - TestController.add_flash_types :foo - assert SubclassesTestController._flash_types.include?(:foo) + test_controller_with_flash_type_foo = Class.new(TestController) do + add_flash_types :foo + end + subclass_controller_with_no_flash_type = Class.new(test_controller_with_flash_type_foo) + assert subclass_controller_with_no_flash_type._flash_types.include?(:foo) end def test_do_not_add_flash_type_to_parent_class - SubclassesTestController.add_flash_types :bar + subclass_controller_with_flash_type_bar = Class.new(TestController) do + add_flash_types :bar + end assert_not TestController._flash_types.include?(:bar) end end -- cgit v1.2.3 From 2bc0271e3df0aa76a1a51fb69b4c780b95cd0bce Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Sun, 6 Apr 2014 21:57:20 +0300 Subject: Added OS X specific commands to installation guide [ci skip] Recommended using homebrew for installing MySQL and PostgreSQL --- guides/source/development_dependencies_install.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 4ee43b6a97..b0e070120d 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -117,7 +117,7 @@ This command will install all dependencies except the MySQL and PostgreSQL Ruby NOTE: If you would like to run the tests that use memcached, you need to ensure that you have it installed and running. -You can use homebrew to install memcached on OSX: +You can use [Homebrew](http://brew.sh/) to install memcached on OSX: ```bash $ brew install memcached @@ -210,6 +210,14 @@ FreeBSD users will have to run the following: # pkg_add -r postgresql92-client postgresql92-server ``` +You can use [Homebrew](http://brew.sh/) to install MySQL and PostgreSQL on OSX: + +```bash +$ brew install mysql +$ brew install postgresql +``` +Follow instructions given by [Homebrew](http://brew.sh/) to start these. + Or install them through ports (they are located under the `databases` folder). If you run into troubles during the installation of MySQL, please see [the MySQL documentation](http://dev.mysql.com/doc/refman/5.1/en/freebsd-installation.html). @@ -245,10 +253,15 @@ $ bundle exec rake mysql:build_databases ``` PostgreSQL's authentication works differently. A simple way to set up the development environment for example is to run with your development account +This is not needed when installed via [Homebrew](http://brew.sh). ```bash $ sudo -u postgres createuser --superuser $USER ``` +And for OS X (when installed via [Homebrew](http://brew.sh)) +```bash +$ createuser --superuser $USER +``` and then create the test databases with -- cgit v1.2.3 From 9534006c47c9aa564a55de714d1e0c8699fd185a Mon Sep 17 00:00:00 2001 From: eileencodes Date: Thu, 3 Apr 2014 18:20:28 -0400 Subject: fix CollectionProxy delete_all documentation This method no longer returns an array of all records that have been removed. Correct documentation to reflect this change. See issue 14546 --- activerecord/lib/active_record/associations/collection_proxy.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 5b71ed163e..84c8cfe72b 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -357,7 +357,7 @@ module ActiveRecord # Deletes all the records from the collection. For +has_many+ associations, # the deletion is done according to the strategy specified by the :dependent - # option. Returns an array with the deleted records. + # option. # # If no :dependent option is given, then it will follow the # default strategy. The default strategy is :nullify. This @@ -435,11 +435,6 @@ module ActiveRecord # # ] # # person.pets.delete_all - # # => [ - # # #, - # # #, - # # # - # # ] # # Pet.find(1, 2, 3) # # => ActiveRecord::RecordNotFound -- cgit v1.2.3 From a44d7107df9b71f747bb0075df05ce9dcac05822 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 7 Apr 2014 10:34:17 +0530 Subject: Remove unused `subclass_controller_with_flash_type_bar` var from flash test. --- actionpack/test/controller/flash_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index ff5587d768..3720a920d0 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -229,8 +229,8 @@ class FlashTest < ActionController::TestCase assert subclass_controller_with_no_flash_type._flash_types.include?(:foo) end - def test_do_not_add_flash_type_to_parent_class - subclass_controller_with_flash_type_bar = Class.new(TestController) do + def test_does_not_add_flash_type_to_parent_class + Class.new(TestController) do add_flash_types :bar end assert_not TestController._flash_types.include?(:bar) -- cgit v1.2.3 From bbe7fe41692e5a2c869f812616d0c99a2bfcb39c Mon Sep 17 00:00:00 2001 From: Evan Whalen Date: Mon, 7 Apr 2014 10:01:03 -0400 Subject: make enums distinct per class --- activerecord/CHANGELOG.md | 7 +++++++ activerecord/lib/active_record/enum.rb | 10 ++++++---- activerecord/test/cases/enum_test.rb | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 16f9db95fc..d39e808f5b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fixed a problem where an enum would overwrite values of another enum + with the same name in an unrelated class. + + Fixes #14607. + + *Evan Whalen* + * PostgreSQL and SQLite string columns no longer have a default limit of 255. Fixes #13435, #9153. diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 4aa323fb00..167f8b7a49 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -65,10 +65,13 @@ module ActiveRecord # # Where conditions on an enum attribute must use the ordinal value of an enum. module Enum - DEFINED_ENUMS = {} # :nodoc: + def self.extended(base) + base.class_attribute(:defined_enums) + base.defined_enums = {} + end def enum_mapping_for(attr_name) # :nodoc: - DEFINED_ENUMS[attr_name.to_s] + defined_enums[attr_name.to_s] end def enum(definitions) @@ -122,9 +125,8 @@ module ActiveRecord klass.send(:detect_enum_conflict!, name, value, true) klass.scope value, -> { klass.where name => i } end - - DEFINED_ENUMS[name.to_s] = enum_values end + defined_enums[name.to_s] = enum_values end end diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index 47de3dec98..5157c272ca 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -250,4 +250,19 @@ class EnumTest < ActiveRecord::TestCase valid_book = klass.new(status: "written") assert valid_book.valid? end + + test "enums are distinct per class" do + Plane = Class.new(ActiveRecord::Base) do + enum status: [:grounded, :operational] + end + assert_equal({ "proposed" => 0, "written" => 1, "published" => 2 }, Book.statuses) + assert_equal({ "grounded" => 0, "operational" => 1 }, Plane.statuses) + end + + test "enums are inheritable" do + Encyclopedia = Class.new(Book) do + enum status: [:published, :reprinted] + end + assert_equal({ "published" => 0, "reprinted" => 1 }, Encyclopedia.statuses) + end end -- cgit v1.2.3 From bbad7523f08936f38938c7d4ff18f4084f008244 Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Mon, 7 Apr 2014 11:07:46 -0300 Subject: Ignore order when doing count. This is necessary because Postgresql doesn't play nice with ORDER BY and no GROUP BY. Fixes #14621. --- activerecord/lib/active_record/relation/calculations.rb | 2 +- activerecord/test/cases/calculations_test.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 45ffb99868..812e3e800a 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -231,7 +231,7 @@ module ActiveRecord def execute_simple_calculation(operation, column_name, distinct) #:nodoc: # Postgresql doesn't like ORDER BY when there are no GROUP BY - relation = reorder(nil) + relation = unscope(:order) column_alias = column_name diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index db999f90ab..b8de78934e 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -387,6 +387,20 @@ class CalculationsTest < ActiveRecord::TestCase assert_raise(ArgumentError) { Account.count(1, 2, 3) } end + def test_count_with_order + assert_equal 6, Account.order(:credit_limit).count + end + + def test_count_with_reverse_order + assert_equal 6, Account.order(:credit_limit).reverse_order.count + end + + def test_count_with_where_and_order + assert_equal 1, Account.where(firm_name: '37signals').count + assert_equal 1, Account.where(firm_name: '37signals').order(:firm_name).count + assert_equal 1, Account.where(firm_name: '37signals').order(:firm_name).reverse_order.count + end + def test_should_sum_expression # Oracle adapter returns floating point value 636.0 after SUM if current_adapter?(:OracleAdapter) -- cgit v1.2.3 From c4bdca19a7a61eb12c75c4a3225e54b69b486a15 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Mon, 7 Apr 2014 22:54:58 +0930 Subject: Use connection-specific bytea escaping In our normal usage, it's rare for this to make a difference... but is more technically correct. As well as a spec that proves this is a good idea, let's also add a more sane-looking one that just covers basic to_sql functionality. There aren't many places where we actually use escape_bytea, but that's one that won't be going away. --- .../connection_adapters/postgresql/quoting.rb | 4 ++-- .../test/cases/adapters/postgresql/bytea_test.rb | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 210172cf32..ac3b0f713d 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -4,14 +4,14 @@ module ActiveRecord module Quoting # Escapes binary strings for bytea input to the database. def escape_bytea(value) - PGconn.escape_bytea(value) if value + @connection.escape_bytea(value) if value end # Unescapes bytea output from a database to the binary string it represents. # NOTE: This is NOT an inverse of escape_bytea! This is only to be used # on escaped binary output from database drive. def unescape_bytea(value) - PGconn.unescape_bytea(value) if value + @connection.unescape_bytea(value) if value end # Quotes PostgreSQL-specific data types for SQL input. diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index c3394d7712..84fa199f17 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -70,6 +70,23 @@ class PostgresqlByteaTest < ActiveRecord::TestCase assert_equal(data, record.payload) end + def test_via_to_sql + data = "'\u001F\\" + record = ByteaDataType.create(payload: data) + sql = ByteaDataType.where(payload: data).select(:payload).to_sql + result = @connection.query(sql) + assert_equal([[data]], result) + end + + def test_via_to_sql_with_complicating_connection + Thread.new do + other_conn = ActiveRecord::Base.connection + other_conn.execute('SET standard_conforming_strings = off') + end.join + + test_via_to_sql + end + def test_write_binary data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log')) assert(data.size > 1) -- cgit v1.2.3 From 6c311e0b7538e8c55797aa889fdf66780ab283a4 Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Mon, 7 Apr 2014 16:01:17 -0300 Subject: Build the reverse_order on its proper method. The reverse_order method was using a flag to control if the order should be reversed or not. Instead of using this variable just build the reverse order inside its proper method. This implementation was leading to an unexpected behavior when using reverse_order and then applying reorder(nil). Example: Before Post.order(:name).reverse_order.reorder(nil) # => SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC After Post.order(:name).reverse_order.reorder(nil) # => SELECT "posts".* FROM "posts" --- activerecord/lib/active_record/relation/merger.rb | 1 - activerecord/lib/active_record/relation/query_methods.rb | 6 +++--- activerecord/test/cases/relation/mutation_test.rb | 14 +++++++++++--- activerecord/test/cases/relations_test.rb | 12 ++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 182b9ed89c..be44fccad5 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -139,7 +139,6 @@ module ActiveRecord def merge_single_values relation.from_value = values[:from] unless relation.from_value relation.lock_value = values[:lock] unless relation.lock_value - relation.reverse_order_value = values[:reverse_order] unless values[:create_with].blank? relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with]) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0213bca981..4287304945 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -825,7 +825,9 @@ module ActiveRecord end def reverse_order! # :nodoc: - self.reverse_order_value = !reverse_order_value + orders = order_values.uniq + orders.reject!(&:blank?) + self.order_values = reverse_sql_order(orders) self end @@ -871,7 +873,6 @@ module ActiveRecord case scope when :order - self.reverse_order_value = false result = [] else result = [] unless single_val_method @@ -1031,7 +1032,6 @@ module ActiveRecord def build_order(arel) orders = order_values.uniq orders.reject!(&:blank?) - orders = reverse_sql_order(orders) if reverse_order_value arel.order(*orders) unless orders.empty? end diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb index 4fafa668fb..c81a3002d6 100644 --- a/activerecord/test/cases/relation/mutation_test.rb +++ b/activerecord/test/cases/relation/mutation_test.rb @@ -107,10 +107,18 @@ module ActiveRecord end test 'reverse_order!' do - assert relation.reverse_order!.equal?(relation) - assert relation.reverse_order_value + relation = Post.order('title ASC, comments_count DESC') + + relation.reverse_order! + + assert_equal 'title DESC', relation.order_values.first + assert_equal 'comments_count ASC', relation.order_values.last + + relation.reverse_order! - assert !relation.reverse_order_value + + assert_equal 'title ASC', relation.order_values.first + assert_equal 'comments_count DESC', relation.order_values.last end test 'create_with!' do diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 049c5a0606..2aa6d643a5 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1424,6 +1424,18 @@ class RelationTest < ActiveRecord::TestCase assert_equal [], scope.references_values end + def test_order_with_reorder_nil_removes_the_order + relation = Post.order(:title).reorder(nil) + + assert_nil relation.order_values.first + end + + def test_reverse_order_with_reorder_nil_removes_the_order + relation = Post.order(:title).reverse_order.reorder(nil) + + assert_nil relation.order_values.first + end + def test_presence topics = Topic.all -- cgit v1.2.3 From 70c83f49f8fcefdf52c2ed22706a14e29559cea5 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 7 Apr 2014 16:53:58 -0300 Subject: Remove useless begin..end --- railties/lib/rails/application.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index dd650e9631..4be90a3f6c 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -151,14 +151,13 @@ module Rails def key_generator # number of iterations selected based on consultation with the google security # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 - @caching_key_generator ||= begin + @caching_key_generator ||= if secrets.secret_key_base key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000) ActiveSupport::CachingKeyGenerator.new(key_generator) else ActiveSupport::LegacyKeyGenerator.new(config.secret_token) end - end end # Returns a message verifier object. -- cgit v1.2.3 From 2512bd717bbf60364935afdbacb422d9248a1ba8 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Mon, 7 Apr 2014 14:16:55 -0400 Subject: remove check for present? from delete_all Passing in a blank string is a bug so there's no reason to check for a blank string. --- activerecord/lib/active_record/associations/collection_association.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index dee7e972c1..803e3ab9ab 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -182,11 +182,11 @@ module ActiveRecord # # See delete for more info. def delete_all(dependent = nil) - if dependent.present? && ![:nullify, :delete_all].include?(dependent) + if dependent && ![:nullify, :delete_all].include?(dependent) raise ArgumentError, "Valid values are :nullify or :delete_all" end - dependent = if dependent.present? + dependent = if dependent dependent elsif options[:dependent] == :destroy :delete_all -- cgit v1.2.3 From e1404ec824d263d25717468c6f4b73ee7b2bdf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 7 Apr 2014 17:33:40 -0300 Subject: Rails.application should be set inside before_configuration hook Fixes #14620 --- railties/lib/rails/application.rb | 4 +++- railties/test/application/multiple_applications_test.rb | 6 ++++++ railties/test/railties/railtie_test.rb | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 4be90a3f6c..8d080feb04 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -87,7 +87,7 @@ module Rails class << self def inherited(base) super - Rails.application ||= base.instance + base.instance end # Makes the +new+ method public. @@ -117,6 +117,8 @@ module Rails @railties = nil @message_verifiers = {} + Rails.application ||= self + add_lib_to_load_path! ActiveSupport.run_load_hooks(:before_configuration, self) diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index 5bfea599e0..42b319178d 100644 --- a/railties/test/application/multiple_applications_test.rb +++ b/railties/test/application/multiple_applications_test.rb @@ -21,6 +21,12 @@ module ApplicationTests assert_equal Rails.application.config.secret_key_base, clone.config.secret_key_base, "The base secret key on the config should be the same" end + def test_inheriting_multiple_times_from_application + new_application_class = Class.new(Rails::Application) + + assert_not_equal Rails.application.object_id, new_application_class.instance.object_id + end + def test_initialization_of_multiple_copies_of_same_application application1 = AppTemplate::Application.new application2 = AppTemplate::Application.new diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 4cbd4822be..a458240d2f 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -72,6 +72,14 @@ module RailtiesTest assert $to_prepare end + test "railtie have access to application in before_configuration callbacks" do + $after_initialize = false + class Foo < Rails::Railtie ; config.before_configuration { $before_configuration = Rails.root.to_path } ; end + assert_not $before_configuration + require "#{app_path}/config/environment" + assert_equal app_path, $before_configuration + end + test "railtie can add after_initialize callbacks" do $after_initialize = false class Foo < Rails::Railtie ; config.after_initialize { $after_initialize = true } ; end -- cgit v1.2.3