diff options
45 files changed, 559 insertions, 213 deletions
diff --git a/actionview/lib/action_view/helpers/atom_feed_helper.rb b/actionview/lib/action_view/helpers/atom_feed_helper.rb index 42b1dd8933..af70a4242a 100644 --- a/actionview/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionview/lib/action_view/helpers/atom_feed_helper.rb @@ -64,7 +64,7 @@ module ActionView # 'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'}) do |feed| # feed.title("My great blog!") # feed.updated((@posts.first.created_at)) - # feed.tag!(openSearch:totalResults, 10) + # feed.tag!('openSearch:totalResults', 10) # # @posts.each do |post| # feed.entry(post) do |entry| diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 9f64941065..fa00d6db1c 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,33 @@ +* Added `ActiveRecord::Base.no_touching`, which allows ignoring touch on models. + + Examples: + + Post.no_touching do + Post.first.touch + end + + *Sam Stephenson*, *Damien Mathieu* + +* Prevent the counter cache from being decremented twice when destroying + a record on a has_many :through association. + + Fixes #11079. + + *Dmitry Dedov* + +* Unify boolean type casting for `MysqlAdapter` and `Mysql2Adapter`. + `type_cast` will return `1` for `true` and `0` for `false`. + + Fixes #11119. + + *Adam Williams*, *Yves Senn* + +* Fix bug where has_one associaton record update result in crash, when replaced with itself. + + Fixes #12834. + + *Denis Redozubov*, *Sergio Cambra* + * Log bind variables after they are type casted. This makes it more transparent what values are actually sent to the database. @@ -8,7 +38,8 @@ *Yves Senn* * Fix uninitialized constant `TransactionState` error when `Marshall.load` is used on an Active Record result. - Fixes #12790 + + Fixes #12790. *Jason Ayre* @@ -108,6 +139,7 @@ *Severin Schoepke* * `ActiveRecord::Store` works together with PG `hstore` columns. + Fixes #12452. *Yves Senn* diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 7a2c5c8bf2..cbac2ef3c6 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -45,6 +45,7 @@ module ActiveRecord autoload :Migrator, 'active_record/migration' autoload :ModelSchema autoload :NestedAttributes + autoload :NoTouching autoload :Persistence autoload :QueryCache autoload :Querying diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 56331bbb0b..31b8d27892 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -163,7 +163,7 @@ module ActiveRecord delete_through_records(records) - if source_reflection.options[:counter_cache] + if source_reflection.options[:counter_cache] && method != :destroy counter = source_reflection.counter_cache_column klass.decrement_counter counter, records.map(&:id) end diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 0008600418..944caacab6 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -26,11 +26,13 @@ module ActiveRecord load_target return self.target if !(target || record) - if (target != record) || record.changed? + + assigning_another_record = target != record + if assigning_another_record || record.changed? save &&= owner.persisted? transaction_if(save) do - remove_target!(options[:dependent]) if target && !target.destroyed? + remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record if record set_owner_attributes(record) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 69a9eabefb..e05e22ebb0 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -295,6 +295,7 @@ module ActiveRecord #:nodoc: extend Delegation::DelegateCache include Persistence + include NoTouching include ReadonlyAttributes include ModelSchema include Inheritance diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 86c27557b4..b5acf211d5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -16,6 +16,7 @@ module ActiveRecord autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do autoload :IndexDefinition autoload :ColumnDefinition + autoload :ChangeColumnDefinition autoload :TableDefinition autoload :Table autoload :AlterTable 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 138ab811dc..ee6ca4fb6f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -206,6 +206,12 @@ module ActiveRecord true end + def type_cast(value, column) + return super unless value == true || value == false + + value ? 1 : 0 + end + # MySQL 4 technically support transaction isolation, but it is affected by a bug # where the transaction level gets persisted for the whole session: # diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index a690404892..7b18b95c44 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -160,12 +160,6 @@ module ActiveRecord # QUOTING ================================================== - def type_cast(value, column) - return super unless value == true || value == false - - value ? 1 : 0 - end - def quote_string(string) #:nodoc: @connection.quote(string) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index eecebdb4e5..adeb57d913 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -631,7 +631,6 @@ module ActiveRecord true end - # Returns true. def supports_explain? true end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 35a579f29b..2cf1015f2c 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -141,14 +141,12 @@ module ActiveRecord 'SQLite' end - # Returns true def supports_ddl_transactions? true end - # Returns true if SQLite version is '3.6.8' or greater, false otherwise. def supports_savepoints? - sqlite_version >= '3.6.8' + true end # Returns true, since this connection adapter supports prepared statement @@ -162,7 +160,6 @@ module ActiveRecord true end - # Returns true. def supports_primary_key? #:nodoc: true end @@ -171,7 +168,6 @@ module ActiveRecord true end - # Returns true def supports_add_column? true end @@ -193,11 +189,6 @@ module ActiveRecord @statements.clear end - # Returns true - def supports_count_distinct? #:nodoc: - true - end - def supports_index_sort_order? true end @@ -218,7 +209,6 @@ module ActiveRecord @connection.encoding.to_s end - # Returns true. def supports_explain? true end diff --git a/activerecord/lib/active_record/no_touching.rb b/activerecord/lib/active_record/no_touching.rb new file mode 100644 index 0000000000..dbf4564ae5 --- /dev/null +++ b/activerecord/lib/active_record/no_touching.rb @@ -0,0 +1,52 @@ +module ActiveRecord + # = Active Record No Touching + module NoTouching + extend ActiveSupport::Concern + + module ClassMethods + # Lets you selectively disable calls to `touch` for the + # duration of a block. + # + # ==== Examples + # ActiveRecord::Base.no_touching do + # Project.first.touch # does nothing + # Message.first.touch # does nothing + # end + # + # Project.no_touching do + # Project.first.touch # does nothing + # Message.first.touch # works, but does not touch the associated project + # end + # + def no_touching(&block) + NoTouching.apply_to(self, &block) + end + end + + class << self + def apply_to(klass) #:nodoc: + klasses.push(klass) + yield + ensure + klasses.pop + end + + def applied_to?(klass) #:nodoc: + klasses.any? { |k| k >= klass } + end + + private + def klasses + Thread.current[:no_touching_classes] ||= [] + end + end + + def no_touching? + NoTouching.applied_to?(self.class) + end + + def touch(*) + super unless no_touching? + end + end +end diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb new file mode 100644 index 0000000000..267aa232d9 --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb @@ -0,0 +1,91 @@ +require "cases/helper" + +class Mysql2BooleanTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + class BooleanType < ActiveRecord::Base + self.table_name = "mysql_booleans" + end + + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table("mysql_booleans") do |t| + t.boolean "archived" + t.string "published", limit: 1 + end + BooleanType.reset_column_information + + @emulate_booleans = ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans + end + + teardown do + emulate_booleans @emulate_booleans + @connection.drop_table "mysql_booleans" + end + + test "column type with emulated booleans" do + emulate_booleans true + + assert_equal :boolean, boolean_column.type + assert_equal :string, string_column.type + end + + test "column type without emulated booleans" do + emulate_booleans false + + assert_equal :integer, boolean_column.type + assert_equal :string, string_column.type + end + + test "test type casting with emulated booleans" do + emulate_booleans true + + boolean = BooleanType.create!(archived: true, published: true) + attributes = boolean.reload.attributes_before_type_cast + + assert_equal 1, attributes["archived"] + assert_equal "1", attributes["published"] + + assert_equal 1, @connection.type_cast(true, boolean_column) + assert_equal 1, @connection.type_cast(true, string_column) + end + + test "test type casting without emulated booleans" do + emulate_booleans false + + boolean = BooleanType.create!(archived: true, published: true) + attributes = boolean.reload.attributes_before_type_cast + + assert_equal 1, attributes["archived"] + assert_equal "1", attributes["published"] + + assert_equal 1, @connection.type_cast(true, boolean_column) + assert_equal 1, @connection.type_cast(true, string_column) + end + + test "with booleans stored as 1 and 0" do + @connection.execute "INSERT INTO mysql_booleans(archived, published) VALUES(1, '1')" + boolean = BooleanType.first + assert_equal true, boolean.archived + assert_equal "1", boolean.published + end + + test "with booleans stored as t" do + @connection.execute "INSERT INTO mysql_booleans(published) VALUES('t')" + boolean = BooleanType.first + assert_equal "t", boolean.published + end + + def boolean_column + BooleanType.columns.find { |c| c.name == 'archived' } + end + + def string_column + BooleanType.columns.find { |c| c.name == 'published' } + end + + def emulate_booleans(value) + ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = value + BooleanType.reset_column_information + end +end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index c450b1beb5..47592f312e 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -514,6 +514,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal(post.taggings.count, post.taggings_count) end + def test_update_counter_caches_on_destroy + post = posts(:welcome) + tag = post.tags.create!(name: 'doomed') + + assert_difference 'post.reload.taggings_count', -1 do + tag.tagged_posts.destroy(post) + end + end + def test_replace_association assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)} diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index cdd386187b..a7a8e0c5c6 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -509,16 +509,30 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_no_queries { Firm.new.account = account } end - def test_has_one_assignment_triggers_save_on_change + def test_has_one_assignment_dont_triggers_save_on_change_of_same_object pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") ship = pirate.build_ship(name: 'old name') ship.save! ship.name = 'new name' assert ship.changed? + assert_queries(1) do + # One query for updating name, not triggering query for updating pirate_id + pirate.ship = ship + end + + assert_equal 'new name', pirate.ship.reload.name + end + + def test_has_one_assignment_triggers_save_on_change_on_replacing_object + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + ship = pirate.build_ship(name: 'old name') + ship.save! + + new_ship = Ship.create(name: 'new name') assert_queries(2) do # One query for updating name and second query for updating pirate_id - pirate.ship = ship + pirate.ship = new_ship end assert_equal 'new name', pirate.ship.reload.name diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb index c171c5e14e..7f99b6841f 100644 --- a/activerecord/test/cases/relation/delegation_test.rb +++ b/activerecord/test/cases/relation/delegation_test.rb @@ -61,8 +61,10 @@ module ActiveRecord end class DelegationRelationTest < DelegationTest + fixtures :comments + def target - Comment.where.not(body: nil) + Comment.where(body: 'Normal type') end [:map, :collect].each do |method| @@ -88,7 +90,7 @@ module ActiveRecord end [:select!, :uniq!].each do |method| - test "##{method} is triggers an immutable error" do + test "##{method} triggers an immutable error" do assert_raises ActiveRecord::ImmutableRelation do assert_responds(target, method) end diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb new file mode 100644 index 0000000000..782c8bc1fd --- /dev/null +++ b/activerecord/test/cases/relation/merging_test.rb @@ -0,0 +1,150 @@ +require 'cases/helper' +require 'models/author' +require 'models/comment' +require 'models/developer' +require 'models/post' +require 'models/project' + +class RelationMergingTest < ActiveRecord::TestCase + fixtures :developers, :comments, :authors, :posts + + def test_relation_merging + devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3")) + assert_equal [developers(:david), developers(:jamis)], devs.to_a + + dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*')) + assert_equal [developers(:poor_jamis)], dev_with_count.to_a + end + + def test_relation_to_sql + sql = Post.connection.unprepared_statement do + Post.first.comments.to_sql + end + assert_no_match(/\?/, sql) + end + + def test_relation_merging_with_arel_equalities_keeps_last_equality + devs = Developer.where(Developer.arel_table[:salary].eq(80000)).merge( + Developer.where(Developer.arel_table[:salary].eq(9000)) + ) + assert_equal [developers(:poor_jamis)], devs.to_a + end + + def test_relation_merging_with_arel_equalities_keeps_last_equality_with_non_attribute_left_hand + salary_attr = Developer.arel_table[:salary] + devs = Developer.where( + Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(80000) + ).merge( + Developer.where( + Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(9000) + ) + ) + assert_equal [developers(:poor_jamis)], devs.to_a + end + + def test_relation_merging_with_eager_load + relations = [] + relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.all) + relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.all) + + relations.each do |posts| + post = posts.find { |p| p.id == 1 } + assert_equal Post.find(1).last_comment, post.last_comment + end + end + + def test_relation_merging_with_locks + devs = Developer.lock.where("salary >= 80000").order("id DESC").merge(Developer.limit(2)) + assert devs.locked.present? + end + + def test_relation_merging_with_preload + [Post.all.merge(Post.preload(:author)), Post.preload(:author).merge(Post.all)].each do |posts| + assert_queries(2) { assert posts.first.author } + end + end + + def test_relation_merging_with_joins + comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day')) + assert_equal 1, comments.count + end + + def test_relation_merging_with_association + assert_queries(2) do # one for loading post, and another one merged query + post = Post.where(:body => 'Such a lovely day').first + comments = Comment.where(:body => 'Thank you for the welcome').merge(post.comments) + assert_equal 1, comments.count + end + end + + test "merge collapses wheres from the LHS only" do + left = Post.where(title: "omg").where(comments_count: 1) + right = Post.where(title: "wtf").where(title: "bbq") + + expected = [left.where_values[1]] + right.where_values + merged = left.merge(right) + + assert_equal expected, merged.where_values + assert !merged.to_sql.include?("omg") + assert merged.to_sql.include?("wtf") + assert merged.to_sql.include?("bbq") + end + + def test_merging_removes_rhs_bind_parameters + left = Post.where(id: Arel::Nodes::BindParam.new('?')) + column = Post.columns_hash['id'] + left.bind_values += [[column, 20]] + right = Post.where(id: 10) + + merged = left.merge(right) + assert_equal [], merged.bind_values + end + + def test_merging_keeps_lhs_bind_parameters + column = Post.columns_hash['id'] + binds = [[column, 20]] + + right = Post.where(id: Arel::Nodes::BindParam.new('?')) + right.bind_values += binds + left = Post.where(id: 10) + + merged = left.merge(right) + assert_equal binds, merged.bind_values + end + + def test_merging_reorders_bind_params + post = Post.first + id_column = Post.columns_hash['id'] + title_column = Post.columns_hash['title'] + + bv = Post.connection.substitute_at id_column, 0 + + right = Post.where(id: bv) + right.bind_values += [[id_column, post.id]] + + left = Post.where(title: bv) + left.bind_values += [[title_column, post.title]] + + merged = left.merge(right) + assert_equal post, merged.first + end +end + +class MergingDifferentRelationsTest < ActiveRecord::TestCase + fixtures :posts, :authors + + test "merging where relations" do + hello_by_bob = Post.where(body: "hello").joins(:author). + merge(Author.where(name: "Bob")).pluck("posts.id") + + assert_equal [posts(:misc_by_bob).id, + posts(:other_by_bob).id], hello_by_bob + end + + test "merging order relations" do + posts_by_author_name = Post.limit(3).joins(:author). + merge(Author.order(:name)).pluck("authors.name") + + assert_equal ["Bob", "Bob", "David"], posts_by_author_name + end +end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index c9c7ac04b3..baa3acf3fb 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -774,75 +774,6 @@ class RelationTest < ActiveRecord::TestCase assert_raises(ArgumentError) { Developer.select } end - def test_relation_merging - devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3")) - assert_equal [developers(:david), developers(:jamis)], devs.to_a - - dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*')) - assert_equal [developers(:poor_jamis)], dev_with_count.to_a - end - - def test_relation_to_sql - sql = Post.connection.unprepared_statement do - Post.first.comments.to_sql - end - assert_no_match(/\?/, sql) - end - - def test_relation_merging_with_arel_equalities_keeps_last_equality - devs = Developer.where(Developer.arel_table[:salary].eq(80000)).merge( - Developer.where(Developer.arel_table[:salary].eq(9000)) - ) - assert_equal [developers(:poor_jamis)], devs.to_a - end - - def test_relation_merging_with_arel_equalities_keeps_last_equality_with_non_attribute_left_hand - salary_attr = Developer.arel_table[:salary] - devs = Developer.where( - Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(80000) - ).merge( - Developer.where( - Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(9000) - ) - ) - assert_equal [developers(:poor_jamis)], devs.to_a - end - - def test_relation_merging_with_eager_load - relations = [] - relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.all) - relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.all) - - relations.each do |posts| - post = posts.find { |p| p.id == 1 } - assert_equal Post.find(1).last_comment, post.last_comment - end - end - - def test_relation_merging_with_locks - devs = Developer.lock.where("salary >= 80000").order("id DESC").merge(Developer.limit(2)) - assert devs.locked.present? - end - - def test_relation_merging_with_preload - [Post.all.merge(Post.preload(:author)), Post.preload(:author).merge(Post.all)].each do |posts| - assert_queries(2) { assert posts.first.author } - end - end - - def test_relation_merging_with_joins - comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day')) - assert_equal 1, comments.count - end - - def test_relation_merging_with_association - assert_queries(2) do # one for loading post, and another one merged query - post = Post.where(:body => 'Such a lovely day').first - comments = Comment.where(:body => 'Thank you for the welcome').merge(post.comments) - assert_equal 1, comments.count - end - end - def test_count posts = Post.all @@ -1597,56 +1528,4 @@ class RelationTest < ActiveRecord::TestCase Array.send(:remove_method, :__omg__) end end - - test "merge collapses wheres from the LHS only" do - left = Post.where(title: "omg").where(comments_count: 1) - right = Post.where(title: "wtf").where(title: "bbq") - - expected = [left.where_values[1]] + right.where_values - merged = left.merge(right) - - assert_equal expected, merged.where_values - assert !merged.to_sql.include?("omg") - assert merged.to_sql.include?("wtf") - assert merged.to_sql.include?("bbq") - end - - def test_merging_removes_rhs_bind_parameters - left = Post.where(id: Arel::Nodes::BindParam.new('?')) - column = Post.columns_hash['id'] - left.bind_values += [[column, 20]] - right = Post.where(id: 10) - - merged = left.merge(right) - assert_equal [], merged.bind_values - end - - def test_merging_keeps_lhs_bind_parameters - column = Post.columns_hash['id'] - binds = [[column, 20]] - - right = Post.where(id: Arel::Nodes::BindParam.new('?')) - right.bind_values += binds - left = Post.where(id: 10) - - merged = left.merge(right) - assert_equal binds, merged.bind_values - end - - def test_merging_reorders_bind_params - post = Post.first - id_column = Post.columns_hash['id'] - title_column = Post.columns_hash['title'] - - bv = Post.connection.substitute_at id_column, 0 - - right = Post.where(id: bv) - right.bind_values += [[id_column, post.id]] - - left = Post.where(title: bv) - left.bind_values += [[title_column, post.title]] - - merged = left.merge(right) - assert_equal post, merged.first - end end diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index 8c6d189b0c..910f46d693 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -78,7 +78,7 @@ module ActiveRecord # ignored SQL, or better yet, use a different notification for the queries # instead examining the SQL content. oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im] - mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/] + mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i] postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i] sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im] diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index ff1b01556d..8c45f2a3f8 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -11,6 +11,7 @@ class TimestampTest < ActiveRecord::TestCase def setup @developer = Developer.first + @owner = Owner.first @developer.update_columns(updated_at: Time.now.prev_month) @previously_updated_at = @developer.updated_at end @@ -92,6 +93,53 @@ class TimestampTest < ActiveRecord::TestCase assert_nothing_raised { Car.first.touch } end + def test_touching_a_no_touching_object + Developer.no_touching do + assert @developer.no_touching? + assert !@owner.no_touching? + @developer.touch + end + + assert !@developer.no_touching? + assert !@owner.no_touching? + assert_equal @previously_updated_at, @developer.updated_at + end + + def test_touching_related_objects + @owner = Owner.first + @previously_updated_at = @owner.updated_at + + Owner.no_touching do + @owner.pets.first.touch + end + + assert_equal @previously_updated_at, @owner.updated_at + end + + def test_global_no_touching + ActiveRecord::Base.no_touching do + assert @developer.no_touching? + assert @owner.no_touching? + @developer.touch + end + + assert !@developer.no_touching? + assert !@owner.no_touching? + assert_equal @previously_updated_at, @developer.updated_at + end + + def test_no_touching_threadsafe + Thread.new do + Developer.no_touching do + assert @developer.no_touching? + + sleep(1) + end + end + + assert !@developer.no_touching? + end + def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at pet = Pet.first owner = pet.owner diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index cda4e7453b..89dab16975 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -485,6 +485,13 @@ class TransactionTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end end + ensure + begin + Topic.connection.remove_column('topics', 'stuff') + rescue + ensure + Topic.reset_column_information + end end def test_transactions_state_from_rollback diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index c0d6e5b70c..3529d57174 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -53,7 +53,7 @@ class Array # ["4", "5"] # ["6", "7"] def in_groups(number, fill_with = nil) - # size / number gives minor group size; + # size.div number gives minor group size; # size % number gives how many objects need extra accommodation; # each group hold either division or division + 1 items. division = size.div number @@ -83,10 +83,10 @@ class Array # # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]] # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]] - def split(value = nil, &block) - if block + def split(value = nil) + if block_given? inject([[]]) do |results, element| - if block.call(element) + if yield(element) results << [] else results.last << element diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 8930376ac8..2684c772ea 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -10,7 +10,7 @@ require 'active_support/core_ext/string/inflections' class Hash # Returns a string containing an XML representation of its receiver: # - # {'foo' => 1, 'bar' => 2}.to_xml + # { foo: 1, bar: 2 }.to_xml # # => # # <?xml version="1.0" encoding="UTF-8"?> # # <hash> @@ -43,7 +43,10 @@ class Hash # end # # { foo: Foo.new }.to_xml(skip_instruct: true) - # # => "<hash><bar>fooing!</bar></hash>" + # # => + # # <hash> + # # <bar>fooing!</bar> + # # </hash> # # * Otherwise, a node with +key+ as tag is created with a string representation of # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added. @@ -201,7 +204,7 @@ module ActiveSupport end def become_empty_string?(value) - # {"string" => true} + # { "string" => true } # No tests fail when the second term is removed. value['type'] == 'string' && value['nil'] != 'true' end diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb index e07db50b77..42fece6c28 100644 --- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -1,13 +1,13 @@ class Hash # Returns a new hash with +self+ and +other_hash+ merged recursively. # - # h1 = { x: { y: [4,5,6] }, z: [7,8,9] } - # h2 = { x: { y: [7,8,9] }, z: 'xyz' } + # h1 = { x: { y: [4, 5, 6] }, z: [7, 8, 9] } + # h2 = { x: { y: [7, 8, 9] }, z: 'xyz' } # - # h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"} - # h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]} + # h1.deep_merge(h2) # => {:x=>{:y=>[7, 8, 9]}, :z=>"xyz"} + # h2.deep_merge(h1) # => {:x=>{:y=>[4, 5, 6]}, :z=>[7, 8, 9]} # h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) } - # #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]} + # # => {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]} def deep_merge(other_hash, &block) dup.deep_merge!(other_hash, &block) end diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index 981e8436bf..970d6faa1d 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -18,5 +18,6 @@ class Hash # # b = { b: 1 } # { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access + # # => {"b"=>32} alias nested_under_indifferent_access with_indifferent_access end diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index b4c451ace4..1845e74c45 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -4,7 +4,7 @@ class Hash # hash = { name: 'Rob', age: '28' } # # hash.transform_keys{ |key| key.to_s.upcase } - # # => { "NAME" => "Rob", "AGE" => "28" } + # # => {"NAME"=>"Rob", "AGE"=>"28"} def transform_keys result = {} each_key do |key| @@ -27,7 +27,7 @@ class Hash # hash = { name: 'Rob', age: '28' } # # hash.stringify_keys - # #=> { "name" => "Rob", "age" => "28" } + # # => {"name"=>"Rob", "age"=>"28"} def stringify_keys transform_keys{ |key| key.to_s } end @@ -44,7 +44,7 @@ class Hash # hash = { 'name' => 'Rob', 'age' => '28' } # # hash.symbolize_keys - # #=> { name: "Rob", age: "28" } + # # => {"name"=>"Rob", "age"=>"28"} def symbolize_keys transform_keys{ |key| key.to_sym rescue key } end @@ -78,7 +78,7 @@ class Hash # hash = { person: { name: 'Rob', age: '28' } } # # hash.deep_transform_keys{ |key| key.to_s.upcase } - # # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } } + # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}} def deep_transform_keys(&block) result = {} each do |key, value| @@ -105,7 +105,7 @@ class Hash # hash = { person: { name: 'Rob', age: '28' } } # # hash.deep_stringify_keys - # # => { "person" => { "name" => "Rob", "age" => "28" } } + # # => {"person"=>{"name"=>"Rob", "age"=>"28"}} def deep_stringify_keys deep_transform_keys{ |key| key.to_s } end @@ -124,7 +124,7 @@ class Hash # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } } # # hash.deep_symbolize_keys - # # => { person: { name: "Rob", age: "28" } } + # # => {:person=>{:name=>"Rob", :age=>"28"}} def deep_symbolize_keys deep_transform_keys{ |key| key.to_sym rescue key } end diff --git a/activesupport/lib/active_support/core_ext/integer/multiple.rb b/activesupport/lib/active_support/core_ext/integer/multiple.rb index 7c6c2f1ca7..c668c7c2eb 100644 --- a/activesupport/lib/active_support/core_ext/integer/multiple.rb +++ b/activesupport/lib/active_support/core_ext/integer/multiple.rb @@ -1,9 +1,9 @@ class Integer # Check whether the integer is evenly divisible by the argument. # - # 0.multiple_of?(0) #=> true - # 6.multiple_of?(5) #=> false - # 10.multiple_of?(2) #=> true + # 0.multiple_of?(0) # => true + # 6.multiple_of?(5) # => false + # 10.multiple_of?(2) # => true def multiple_of?(number) number != 0 ? self % number == 0 : zero? end diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb index 36ab836457..df11737a6b 100644 --- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb +++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb @@ -60,8 +60,7 @@ module Kernel # puts 'This code gets executed and nothing related to ZeroDivisionError was seen' def suppress(*exception_classes) yield - rescue Exception => e - raise unless exception_classes.any? { |cls| e.kind_of?(cls) } + rescue *exception_classes end # Captures the given stream and returns it: diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index 38e407b198..4cfc5b1f10 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1,3 +1,7 @@ +* Fixed missing line and shadow on service pages(404, 422, 500). + + *Dmitry Korotkov* + * Removed repetitive th tags. Instead of them added one th tag with a colspan attribute. *Sıtkı Bağdat* diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb index 693bc320b3..89ac28671a 100644 --- a/guides/bug_report_templates/action_controller_gem.rb +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -19,6 +19,8 @@ class TestApp < Rails::Application end class TestController < ActionController::Base + include Rails.application.routes.url_helpers + def index render text: 'Home' end diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb index 5d88749118..d44fd9196a 100644 --- a/guides/bug_report_templates/action_controller_master.rb +++ b/guides/bug_report_templates/action_controller_master.rb @@ -28,6 +28,8 @@ class TestApp < Rails::Application end class TestController < ActionController::Base + include Rails.application.routes.url_helpers + def index render text: 'Home' end diff --git a/guides/code/getting_started/public/404.html b/guides/code/getting_started/public/404.html index 3d287b135d..3265cc8e33 100644 --- a/guides/code/getting_started/public/404.html +++ b/guides/code/getting_started/public/404.html @@ -22,6 +22,7 @@ border-top-right-radius: 9px; background-color: white; padding: 7px 4em 0 4em; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -37,6 +38,7 @@ background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; diff --git a/guides/code/getting_started/public/422.html b/guides/code/getting_started/public/422.html index 3b946bf4a4..d823a8fc77 100644 --- a/guides/code/getting_started/public/422.html +++ b/guides/code/getting_started/public/422.html @@ -22,6 +22,7 @@ border-top-right-radius: 9px; background-color: white; padding: 7px 4em 0 4em; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -37,6 +38,7 @@ background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; diff --git a/guides/code/getting_started/public/500.html b/guides/code/getting_started/public/500.html index ccc4ad5656..ebf6d4c00c 100644 --- a/guides/code/getting_started/public/500.html +++ b/guides/code/getting_started/public/500.html @@ -22,6 +22,7 @@ border-top-right-radius: 9px; background-color: white; padding: 7px 4em 0 4em; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -37,6 +38,7 @@ background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index b72ebd63ee..648036fb3f 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -37,9 +37,10 @@ For every single method defined as a core extension this guide has a note that s NOTE: Defined in `active_support/core_ext/object/blank.rb`. -That means that this single call is enough: +That means that you can require it like this: ```ruby +require 'active_support' require 'active_support/core_ext/object/blank' ``` @@ -52,6 +53,7 @@ The next level is to simply load all extensions to `Object`. As a rule of thumb, Thus, to load all extensions to `Object` (including `blank?`): ```ruby +require 'active_support' require 'active_support/core_ext/object' ``` @@ -60,6 +62,7 @@ require 'active_support/core_ext/object' You may prefer just to load all core extensions, there is a file for that: ```ruby +require 'active_support' require 'active_support/core_ext' ``` diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index b5d66d08ba..c6a3449ace 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -122,8 +122,7 @@ X-Runtime: 0.014297 Set-Cookie: _blog_session=...snip...; path=/; HttpOnly Cache-Control: no-cache - - $ +$ ``` We see there is an empty response (no data after the `Cache-Control` line), but the request was successful because Rails has set the response to 200 OK. You can set the `:status` option on render to change this response. Rendering nothing can be useful for Ajax requests where all you want to send back to the browser is an acknowledgment that the request was completed. @@ -137,7 +136,7 @@ If you want to render the view that corresponds to a different template within t ```ruby def update @book = Book.find(params[:id]) - if @book.update(params[:book]) + if @book.update(book_params) redirect_to(@book) else render "edit" @@ -152,7 +151,7 @@ If you prefer, you can use a symbol instead of a string to specify the action to ```ruby def update @book = Book.find(params[:id]) - if @book.update(params[:book]) + if @book.update(book_params) redirect_to(@book) else render :edit diff --git a/guides/source/migrations.md b/guides/source/migrations.md index b7283d16cc..71a177bca7 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -420,7 +420,7 @@ If the helpers provided by Active Record aren't enough you can use the `execute` method to execute arbitrary SQL: ```ruby -Products.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') +Product.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') ``` For more details and examples of individual methods, check the API documentation. diff --git a/guides/source/security.md b/guides/source/security.md index d7a41497f8..595cf7c62c 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -17,7 +17,7 @@ After reading this guide, you will know: Introduction ------------ -Web application frameworks are made to help developers building web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security. +Web application frameworks are made to help developers build web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security. In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications). diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 0dddee0555..bf09066cf1 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,11 @@ +* Support for Pathnames in eager load paths. + + *Mike Pack* + +* Fixed missing line and shadow on service pages(404, 422, 500). + + *Dmitry Korotkov* + * `BACKTRACE` environment variable to show unfiltered backtraces for test failures. diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index e8adef2fd3..1296c0a843 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -465,7 +465,7 @@ module Rails # files inside eager_load paths. def eager_load! config.eager_load_paths.each do |load_path| - matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/ + matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/ Dir.glob("#{load_path}/**/*.rb").sort.each do |file| require_dependency file.sub(matcher, '\1') end diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index a0daa0c156..7d99be2ecf 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -2,17 +2,23 @@ <html> <head> <title>The page you were looking for doesn't exist (404)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> <style> body { background-color: #EFEFEF; color: #2E2F30; text-align: center; font-family: arial, sans-serif; + margin: 0; } div.dialog { - width: 25em; - margin: 4em auto 0 auto; + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -21,7 +27,8 @@ border-top-left-radius: 9px; border-top-right-radius: 9px; background-color: white; - padding: 7px 4em 0 4em; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -30,19 +37,19 @@ line-height: 1.5em; } - body > p { - width: 33em; - margin: 0 auto 1em; - padding: 1em 0; + div.dialog > p { + margin: 0 0 1em; + padding: 1em; background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-top-color: #DADADA; color: #666; - box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } </style> </head> @@ -50,9 +57,11 @@ <body> <!-- This file lives in public/404.html --> <div class="dialog"> - <h1>The page you were looking for doesn't exist.</h1> - <p>You may have mistyped the address or the page may have moved.</p> + <div> + <h1>The page you were looking for doesn't exist.</h1> + <p>You may have mistyped the address or the page may have moved.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> </div> - <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index fbb4b84d72..ee18eeb10c 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html @@ -2,17 +2,23 @@ <html> <head> <title>The change you wanted was rejected (422)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> <style> body { background-color: #EFEFEF; color: #2E2F30; text-align: center; font-family: arial, sans-serif; + margin: 0; } div.dialog { - width: 25em; - margin: 4em auto 0 auto; + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -21,7 +27,8 @@ border-top-left-radius: 9px; border-top-right-radius: 9px; background-color: white; - padding: 7px 4em 0 4em; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -30,19 +37,19 @@ line-height: 1.5em; } - body > p { - width: 33em; - margin: 0 auto 1em; - padding: 1em 0; + div.dialog > p { + margin: 0 0 1em; + padding: 1em; background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-top-color: #DADADA; color: #666; - box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } </style> </head> @@ -50,9 +57,11 @@ <body> <!-- This file lives in public/422.html --> <div class="dialog"> - <h1>The change you wanted was rejected.</h1> - <p>Maybe you tried to change something you didn't have access to.</p> + <div> + <h1>The change you wanted was rejected.</h1> + <p>Maybe you tried to change something you didn't have access to.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> </div> - <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index e9052d35bf..e4161c3ce5 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -2,17 +2,23 @@ <html> <head> <title>We're sorry, but something went wrong (500)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> <style> body { background-color: #EFEFEF; color: #2E2F30; text-align: center; font-family: arial, sans-serif; + margin: 0; } div.dialog { - width: 25em; - margin: 4em auto 0 auto; + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -21,7 +27,8 @@ border-top-left-radius: 9px; border-top-right-radius: 9px; background-color: white; - padding: 7px 4em 0 4em; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } h1 { @@ -30,19 +37,19 @@ line-height: 1.5em; } - body > p { - width: 33em; - margin: 0 auto 1em; - padding: 1em 0; + div.dialog > p { + margin: 0 0 1em; + padding: 1em; background-color: #F7F7F7; border: 1px solid #CCC; border-right-color: #999; + border-left-color: #999; border-bottom-color: #999; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-top-color: #DADADA; color: #666; - box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } </style> </head> @@ -50,8 +57,10 @@ <body> <!-- This file lives in public/500.html --> <div class="dialog"> - <h1>We're sorry, but something went wrong.</h1> + <div> + <h1>We're sorry, but something went wrong.</h1> + </div> + <p>If you are the application owner check the logs for more information.</p> </div> - <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index b36628ee37..cd05956356 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -71,6 +71,20 @@ module ApplicationTests assert Zoo end + test "eager loading accepts Pathnames" do + app_file "lib/foo.rb", <<-RUBY + module Foo; end + RUBY + + add_to_config <<-RUBY + config.eager_load = true + config.eager_load_paths << Pathname.new("#{app_path}/lib") + RUBY + + require "#{app_path}/config/environment" + assert Foo + end + test "load environment with global" do $initialize_test_set_from_env = nil app_file "config/environments/development.rb", <<-RUBY diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 42096cfec4..9145cb6936 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -73,7 +73,7 @@ module ApplicationTests assert_nothing_raised(ActionController::RoutingError) do get '/foo' - assert_match "The page you were looking for doesn't exist.", last_response.body + assert_match "The page you were looking for doesn't exist.", last_response.body end end |