From 6c2d974e152850b533dafc6654d0df7bddfbd4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 9 May 2010 12:52:26 +0300 Subject: Use annoted source code in Template:Error to avoid special cases in the show exceptions middleware. --- actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 12 ++++-------- actionpack/lib/action_view/template/error.rb | 5 ++--- actionpack/test/template/render_test.rb | 1 + 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 12a93d6a24..2dd2ec9fe9 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -133,14 +133,10 @@ module ActionDispatch return unless logger ActiveSupport::Deprecation.silence do - if ActionView::Template::Error === exception - logger.fatal(exception.to_s) - else - logger.fatal( - "\n#{exception.class} (#{exception.message}):\n " + - clean_backtrace(exception).join("\n ") + "\n\n" - ) - end + message = "\n#{exception.class} (#{exception.message}):\n" + message << exception.annoted_source_code if exception.respond_to?(:annoted_source_code) + message << exception.backtrace.join("\n ") + logger.fatal("#{message}\n\n") end end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index a947d746e3..6866eabf77 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -84,9 +84,8 @@ module ActionView end end - def to_s - "\n#{self.class} (#{message}) #{source_location}:\n\n" + - "#{source_extract(4)}\n #{backtrace.join("\n ")}\n\n" + def annoted_source_code + source_extract(4) end private diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index c9a50da418..d0212024ae 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -111,6 +111,7 @@ module RenderTestCases assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number + assert_equal "1: <%= doesnt_exist %>", e.annoted_source_code.strip assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end -- cgit v1.2.3 From 231d7676f72947bae765b9bd885b134aaf949921 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sun, 9 May 2010 12:24:25 +0300 Subject: corrected AR find_each and find_in_batches to raise when the user uses select but does not specify the primary key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/lib/active_record/relation/batches.rb | 9 ++++++++- activerecord/test/cases/batches_test.rb | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 1c61e7d450..4649e3b376 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -67,11 +67,18 @@ module ActiveRecord relation = relation.except(:order).order(batch_order).limit(batch_size) records = relation.where(primary_key.gteq(start)).all + key_value = self.primary_key.name + while records.any? yield records break if records.size < batch_size - records = relation.where(primary_key.gt(records.last.id)).all + + last_value = records.last.send(key_value) + + raise "You must include the primary key if you define a select" unless last_value.present? + + records = relation.where(primary_key.gt(last_value)).all end end diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 83deabb5b7..dcc49e12ca 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -17,6 +17,20 @@ class EachTest < ActiveRecord::TestCase end end + def test_each_should_raise_if_select_is_set_without_id + assert_raise(RuntimeError) do + Post.find_each(:select => :title, :batch_size => 1) { |post| post } + end + end + + def test_each_should_execute_if_id_is_in_select + assert_queries(4) do + Post.find_each(:select => "id, title, type", :batch_size => 2) do |post| + assert_kind_of Post, post + end + end + end + def test_each_should_raise_if_the_order_is_set assert_raise(RuntimeError) do Post.find_each(:order => "title") { |post| post } -- cgit v1.2.3 From f75a6fec2947ce23bd3ca4911d2d798415ccd355 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 9 May 2010 12:30:45 +0100 Subject: Improve code from 231d7676f72947bae765b9bd885b134aaf949921 --- activerecord/lib/active_record/relation/batches.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 4649e3b376..412be895c4 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -67,18 +67,16 @@ module ActiveRecord relation = relation.except(:order).order(batch_order).limit(batch_size) records = relation.where(primary_key.gteq(start)).all - key_value = self.primary_key.name - while records.any? yield records break if records.size < batch_size - last_value = records.last.send(key_value) - - raise "You must include the primary key if you define a select" unless last_value.present? - - records = relation.where(primary_key.gt(last_value)).all + if primary_key_offset = records.last.id + records = relation.where(primary_key.gt(primary_key_offset)).all + else + raise "Primary key not included in the custom select clause" + end end end -- cgit v1.2.3 From 8d2f6c16e381f5fff6d3f24f5c73a443577a1488 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 9 May 2010 12:42:48 +0100 Subject: Revert "Revert "Add index length support for MySQL [#1852 state:open]"" This reverts commit 6626833db13a69786f9f6cd56b9f53c4017c3e39. --- activerecord/CHANGELOG | 10 ++++++++++ .../abstract/schema_definitions.rb | 2 +- .../abstract/schema_statements.rb | 23 +++++++++++++++++++++- .../connection_adapters/mysql_adapter.rb | 15 +++++++++++++- activerecord/lib/active_record/schema_dumper.rb | 1 + .../test/cases/active_schema_test_mysql.rb | 17 ++++++++++++++++ activerecord/test/cases/migration_test.rb | 8 ++++++++ 7 files changed, 73 insertions(+), 3 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 3f42fa34ef..d8f68d7c28 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,15 @@ *Rails 3.0.0 [beta 4/release candidate] (unreleased)* +* Add index length support for MySQL. #1852 [Emili Parreno, Pratik Naik] + + Example: + + add_index(:accounts, :name, :name => 'by_name', :length => 10) + => CREATE INDEX by_name ON accounts(name(10)) + + add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15}) + => CREATE INDEX by_name_surname ON accounts(name(10), surname(15)) + * find_or_create_by_attr(value, ...) works when attr is protected. #4457 [Santiago Pastorino, Marc-André Lafortune] * New callbacks: after_commit and after_rollback. Do expensive operations like image thumbnailing after_commit instead of after_save. #2991 [Brian Durand] 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 6c477e48ce..e42cd99786 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -258,7 +258,7 @@ module ActiveRecord end end - class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc: + class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc: end # Abstract representation of a column definition. Instances of this type 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 e8cba1bd41..1255ef09be 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -256,18 +256,32 @@ module ActiveRecord # name. # # ===== Examples + # # ====== Creating a simple index # add_index(:suppliers, :name) # generates # CREATE INDEX suppliers_name_index ON suppliers(name) + # # ====== Creating a unique index # add_index(:accounts, [:branch_id, :party_id], :unique => true) # generates # CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id) + # # ====== Creating a named index # add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party') # generates # CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id) + # + # ====== Creating an index with specific key length + # add_index(:accounts, :name, :name => 'by_name', :length => 10) + # generates + # CREATE INDEX by_name ON accounts(name(10)) + # + # add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15}) + # generates + # CREATE INDEX by_name_surname ON accounts(name(10), surname(15)) + # + # Note: SQLite doesn't support index length def add_index(table_name, column_name, options = {}) column_names = Array.wrap(column_name) index_name = index_name(table_name, :column => column_names) @@ -278,7 +292,9 @@ module ActiveRecord else index_type = options end - quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ") + + quoted_column_names = quoted_columns_for_index(column_names, options).join(", ") + execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})" end @@ -430,6 +446,11 @@ module ActiveRecord end protected + # Overridden by the mysql adapter for supporting index lengths + def quoted_columns_for_index(column_names, options = {}) + column_names.map {|name| quote_column_name(name) } + 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/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 55d9d20bb5..470ff8d767 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -461,10 +461,11 @@ module ActiveRecord if current_index != row[2] next if row[2] == "PRIMARY" # skip the primary key current_index = row[2] - indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", []) + indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [], []) end indexes.last.columns << row[4] + indexes.last.lengths << row[7] end result.free indexes @@ -594,6 +595,18 @@ module ActiveRecord end protected + def quoted_columns_for_index(column_names, options = {}) + length = options[:length] if options.is_a?(Hash) + + quoted_column_names = case length + when Hash + column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } + when Fixnum + column_names.map {|name| "#{quote_column_name(name)}(#{length})"} + else + column_names.map {|name| quote_column_name(name) } + end + end def translate_exception(exception, message) return super unless exception.respond_to?(:errno) diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index c8e1b4f53a..5cb639a300 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -177,6 +177,7 @@ HEADER statment_parts << index.columns.inspect statment_parts << (':name => ' + index.name.inspect) statment_parts << ':unique => true' if index.unique + statment_parts << (':length => ' + Hash[*index.columns.zip(index.lengths).flatten].inspect) if index.lengths.compact.present? ' ' + statment_parts.join(', ') end diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index 9aff538ce9..f4d123be15 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -15,6 +15,23 @@ class ActiveSchemaTest < ActiveRecord::TestCase end end + def test_add_index + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)" + assert_equal expected, add_index(:people, :last_name, :length => nil) + + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10))" + assert_equal expected, add_index(:people, :last_name, :length => 10) + + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15))" + assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15) + + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`)" + assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15}) + + expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))" + assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) + end + def test_drop_table assert_equal "DROP TABLE `people`", drop_table(:people) end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index a3d1ceaa1f..f67344445a 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -92,6 +92,14 @@ if ActiveRecord::Base.connection.supports_migrations? assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") } assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :length => 10) } + assert_nothing_raised { Person.connection.remove_index("people", "last_name") } + assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :length => {:last_name => 10}) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :length => 10) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :length => {:last_name => 10, :first_name => 20}) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } end # quoting -- cgit v1.2.3 From ce5827ea4791e8b8143919ecceb0231e36e8932e Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 9 May 2010 12:42:15 +0100 Subject: Make sure schema dumper doesnt throw up when there are no index lengths --- activerecord/lib/active_record/schema_dumper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 5cb639a300..cd54653581 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -177,7 +177,9 @@ HEADER statment_parts << index.columns.inspect statment_parts << (':name => ' + index.name.inspect) statment_parts << ':unique => true' if index.unique - statment_parts << (':length => ' + Hash[*index.columns.zip(index.lengths).flatten].inspect) if index.lengths.compact.present? + + index_lengths = index.lengths.compact if index.lengths.is_a?(Array) + statment_parts << (':length => ' + Hash[*index.columns.zip(index.lengths).flatten].inspect) if index_lengths.present? ' ' + statment_parts.join(', ') end -- cgit v1.2.3 From 5c245b91d2dbc0b300e8193310b3f950d0cf6c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 10 May 2010 12:28:38 +0300 Subject: Make sure valid? preceives the context as in ActiveModel API (ht: Carlos Antonio) --- .../active_record/attribute_methods/primary_key.rb | 2 +- activerecord/lib/active_record/validations.rb | 47 ++++++++++------------ activerecord/test/cases/validations_test.rb | 17 ++++++++ activerecord/test/models/reply.rb | 5 +++ 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 411330dda2..82d94b848a 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -6,7 +6,7 @@ module ActiveRecord # Returns this record's primary key value wrapped in an Array # or nil if the record is a new_record? def to_key - new_record? ? nil : [ send(self.class.primary_key) ] + new_record? ? nil : [ id ] end module ClassMethods diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 55c4236874..58391168a9 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -36,8 +36,8 @@ module ActiveRecord # The validation process on save can be skipped by passing false. The regular Base#save method is # replaced with this when the validations module is mixed in, which it is by default. - def save(options=nil) - return super if valid?(options) + def save(options={}) + return super if perform_validations(options) false end @@ -47,38 +47,35 @@ module ActiveRecord # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false # if the record is not valid. - def save!(options = nil) - return super if valid?(options) + def save!(options={}) + return super if perform_validations(options) raise RecordInvalid.new(self) end # Runs all the specified validations and returns true if no errors were added otherwise false. - def valid?(options = nil) - perform_validation = case options - when NilClass - true - when Hash - options[:validate] != false - else - ActiveSupport::Deprecation.warn "save(#{options}) is deprecated, please give save(:validate => #{options}) instead", caller - options - end + def valid?(context = nil) + context ||= (new_record? ? :create : :update) + super(context) - if perform_validation - errors.clear + deprecated_callback_method(:validate) + deprecated_callback_method(:"validate_on_#{context}") - self.validation_context = new_record? ? :create : :update - _run_validate_callbacks + errors.empty? + end - deprecated_callback_method(:validate) + protected - if new_record? - deprecated_callback_method(:validate_on_create) - else - deprecated_callback_method(:validate_on_update) - end + def perform_validations(options={}) + perform_validation = case options + when Hash + options[:validate] != false + else + ActiveSupport::Deprecation.warn "save(#{options}) is deprecated, please give save(:validate => #{options}) instead", caller + options + end - errors.empty? + if perform_validation + valid?(options.is_a?(Hash) ? options[:context] : nil) else true end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index e1fb911cc9..b873babc36 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -62,6 +62,23 @@ class ValidationsTest < ActiveRecord::TestCase assert_equal ["is Wrong Update"], r.errors[:title], "A reply with a bad content should contain an error" end + def test_error_on_given_context + r = WrongReply.new + assert !r.valid?(:special_case) + assert "Invalid", r.errors[:title].join + + r.title = "secret" + r.content = "Good" + assert r.valid?(:special_case) + + r.title = nil + assert !r.save(:context => :special_case) + assert "Invalid", r.errors[:title].join + + r.title = "secret" + assert r.save(:context => :special_case) + end + def test_invalid_record_exception assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! } assert_raise(ActiveRecord::RecordInvalid) { WrongReply.new.save! } diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index 264a49b465..6cc9ee038a 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -17,6 +17,7 @@ class WrongReply < Reply validate :check_empty_title validate :check_content_mismatch, :on => :create validate :check_wrong_update, :on => :update + validate :check_title_is_secret, :on => :special_case def check_empty_title errors[:title] << "Empty" unless attribute_present?("title") @@ -39,6 +40,10 @@ class WrongReply < Reply def check_wrong_update errors[:title] << "is Wrong Update" if attribute_present?("title") && title == "Wrong Update" end + + def check_title_is_secret + errors[:title] << "Invalid" unless title == "secret" + end end class SillyReply < Reply -- cgit v1.2.3 From 446b0ffe1c804f4925867d785b9709d21105c707 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sun, 9 May 2010 17:14:48 +0300 Subject: corrected error message in session/cookie_store [#4546 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/middleware/session/cookie_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 88ba941676..7114f42003 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -177,7 +177,7 @@ module ActionDispatch if key.blank? raise ArgumentError, 'A key is required to write a ' + 'cookie containing the session data. Use ' + - 'config.action_controller.session_store :cookie_store, { :key => ' + + 'config.session_store :cookie_store, { :key => ' + '"_myapp_session" } in config/application.rb' end end -- cgit v1.2.3 From 1f675ea8c731328aa4ba14187ba529f0b53fbf0d Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 11 May 2010 13:45:57 +0100 Subject: Succint save definition --- activerecord/lib/active_record/validations.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 58391168a9..7a6fef0b7b 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -37,8 +37,7 @@ module ActiveRecord # The validation process on save can be skipped by passing false. The regular Base#save method is # replaced with this when the validations module is mixed in, which it is by default. def save(options={}) - return super if perform_validations(options) - false + perform_validations(options) ? super : false end def save_without_validation! @@ -48,8 +47,7 @@ module ActiveRecord # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false # if the record is not valid. def save!(options={}) - return super if perform_validations(options) - raise RecordInvalid.new(self) + perform_validations(options) ? super : raise(RecordInvalid.new(self)) end # Runs all the specified validations and returns true if no errors were added otherwise false. -- cgit v1.2.3 From 475d1d1713faddee890e2367724a629169e079fe Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 11 May 2010 15:32:41 +0100 Subject: Use arel instead of sql strings --- activerecord/lib/active_record/locking/optimistic.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 71057efa15..ceb0902fde 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -113,12 +113,11 @@ module ActiveRecord lock_col = self.class.locking_column previous_value = send(lock_col).to_i - affected_rows = connection.delete( - "DELETE FROM #{self.class.quoted_table_name} " + - "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id} " + - "AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}", - "#{self.class.name} Destroy" - ) + table = self.class.arel_table + predicate = table[self.class.primary_key].eq(id) + predicate = predicate.and(table[self.class.locking_column].eq(previous_value)) + + affected_rows = self.class.unscoped.where(predicate).delete_all unless affected_rows == 1 raise ActiveRecord::StaleObjectError, "Attempted to delete a stale object: #{self.class.name}" -- cgit v1.2.3 From 88b4a8fcafc7c52ad7deaa4fee9ee0fabf68940c Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 11 May 2010 15:39:29 +0100 Subject: Remove undocumented save_without_validation! --- activerecord/lib/active_record/validations.rb | 4 ---- activerecord/test/cases/validations_test.rb | 6 ------ 2 files changed, 10 deletions(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 7a6fef0b7b..be64e00bd1 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -40,10 +40,6 @@ module ActiveRecord perform_validations(options) ? super : false end - def save_without_validation! - save!(:validate => false) - end - # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false # if the record is not valid. def save!(options={}) diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index b873babc36..3a34df2426 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -152,12 +152,6 @@ class ValidationsTest < ActiveRecord::TestCase end end - def test_create_without_validation_bang - count = WrongReply.count - assert_nothing_raised { WrongReply.new.save_without_validation! } - assert count+1, WrongReply.count - end - def test_validates_acceptance_of_with_non_existant_table Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base) -- cgit v1.2.3 From a4207c1084439051ca0d828768382bcff86c5d92 Mon Sep 17 00:00:00 2001 From: Blake Smith Date: Tue, 11 May 2010 12:52:47 -0500 Subject: Make sure timestamp is properly referenced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/lib/active_record/attribute_methods/dirty.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index dd44bd8d51..cf4594ad7f 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -8,7 +8,7 @@ module ActiveRecord include AttributeMethods::Write included do - if self < Timestamp + if self < ::ActiveRecord::Timestamp raise "You cannot include Dirty after Timestamp" end -- cgit v1.2.3 From 75ddbfecde6452b233540c67b93057f124726638 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 12 May 2010 00:37:23 +0200 Subject: Gemfile requires sqlite3-ruby 1.3.0.beta.1 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index f5968827a1..5a8879d38e 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ group :mri do end # AR -gem "sqlite3-ruby", ">= 1.2.5", :require => 'sqlite3' +gem "sqlite3-ruby", "= 1.3.0.beta.1", :require => 'sqlite3' group :db do gem "pg", ">= 0.9.0" -- cgit v1.2.3 From 5f3bd55726703e08ba595555e1cf428c57832603 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 12 May 2010 01:47:58 -0300 Subject: type_cast_calculated_value refactor: value is never a Fixnum here. Fix test since SQLite returns Float. [#4514 state:committed] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/relation/calculations.rb | 2 +- activerecord/test/cases/calculations_test.rb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 858d298470..0e11f89c8b 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -243,7 +243,7 @@ module ActiveRecord case operation when 'count' then value.to_i when 'sum' then type_cast_using_column(value || '0', column) - when 'average' then value && (value.is_a?(Fixnum) ? value.to_f : value).to_d + when 'average' then value.try(:to_d) else type_cast_using_column(value, column) end else diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 28a1ae5feb..8473150338 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -20,8 +20,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_average_field value = Account.average(:credit_limit) - assert_kind_of BigDecimal, value - assert_equal BigDecimal.new('53.0'), value + assert_equal 53.0, value end def test_should_return_nil_as_average -- cgit v1.2.3 From 7321a3a7d314585093d08c098eca38afd3b57b00 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 12 May 2010 08:47:55 +0200 Subject: revises the rdoc of #average according to 5f3bd55, and realigns when clauses --- activerecord/lib/active_record/relation/calculations.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 0e11f89c8b..44baeb6c84 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -45,9 +45,8 @@ module ActiveRecord calculate(:count, column_name, options) end - # Calculates the average value on a given column. The value is returned as - # a float, or +nil+ if there's no row. See +calculate+ for examples with - # options. + # Calculates the average value on a given column. Returns +nil+ if there's + # no row. See +calculate+ for examples with options. # # Person.average('age') # => 35.8 def average(column_name, options = {}) @@ -241,8 +240,8 @@ module ActiveRecord def type_cast_calculated_value(value, column, operation = nil) if value.is_a?(String) || value.nil? case operation - when 'count' then value.to_i - when 'sum' then type_cast_using_column(value || '0', column) + when 'count' then value.to_i + when 'sum' then type_cast_using_column(value || '0', column) when 'average' then value.try(:to_d) else type_cast_using_column(value, column) end -- cgit v1.2.3 From 42fa2714c5005bb50679bf9a081d8bf0774f7eec Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 4 May 2010 22:27:17 -0300 Subject: Make use of to_xml and to_json in tests Signed-off-by: Jeremy Kemper --- activeresource/test/cases/base_test.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index 2ed7e1c95f..e5f556962b 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -1009,7 +1009,10 @@ class BaseTest < Test::Unit::TestCase def test_to_xml matz = Person.find(1) - xml = matz.encode + encode = matz.encode + xml = matz.to_xml + + assert encode, xml assert xml.include?('') assert xml.include?('Matz') assert xml.include?('1') @@ -1019,9 +1022,11 @@ class BaseTest < Test::Unit::TestCase Person.include_root_in_json = true Person.format = :json joe = Person.find(6) - json = joe.encode + encode = joe.encode + json = joe.to_json Person.format = :xml + assert encode, json assert_match %r{^\{"person":\{"person":\{}, json assert_match %r{"id":6}, json assert_match %r{"name":"Joe"}, json -- cgit v1.2.3 From f7862b2c34b5b298bf7b937c55f0637ebfe43a25 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 12 May 2010 00:18:42 -0300 Subject: Refactor of active_model/naming.rb and allow collection and element to be writable Signed-off-by: Jeremy Kemper --- activemodel/lib/active_model/naming.rb | 34 +++++++++++++++++++++++++++++----- activemodel/test/cases/naming_test.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 8cdd3d2fe8..a860388bae 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -3,18 +3,36 @@ require 'active_support/inflector' module ActiveModel class Name < String - attr_reader :singular, :plural, :element, :collection, :partial_path - alias_method :cache_key, :collection + attr_reader :singular, :plural, :element def initialize(klass) super(klass.name) @klass = klass @singular = ActiveSupport::Inflector.underscore(self).tr('/', '_').freeze @plural = ActiveSupport::Inflector.pluralize(@singular).freeze - @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze + @collection = nil + self.element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze + end + + def element=(element) + @element = element @human = ActiveSupport::Inflector.humanize(@element).freeze - @collection = ActiveSupport::Inflector.tableize(self).freeze - @partial_path = "#{@collection}/#{@element}".freeze + @default_collection = nil + @partial_path = nil + end + + def collection + @collection || default_collection + end + alias_method :cache_key, :collection + + def collection=(collection) + @collection = collection + @partial_path = nil + end + + def partial_path + @partial_path ||= "#{collection}/#{@element}" end # Transform the model name into a more humane format, using I18n. By default, @@ -34,6 +52,12 @@ module ActiveModel options.reverse_merge! :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults I18n.translate(defaults.shift, options) end + + private + + def default_collection + @default_collection ||= ActiveSupport::Inflector.tableize(self.sub(/[^:]*$/, @element)).freeze + end end # ActiveModel::Naming is a module that creates a +model_name+ method on your diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index dc39b84ed8..3918002360 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -18,6 +18,26 @@ class NamingTest < ActiveModel::TestCase assert_equal 'track_back', @model_name.element end + def test_set_element + @model_name.element = 'foo' + + assert_equal 'foo', @model_name.element + assert_equal 'Foo', @model_name.human + assert_equal 'post/foos', @model_name.collection + assert_equal 'post/foos/foo', @model_name.partial_path + end + + def test_human + assert_equal 'Track back', @model_name.human + end + + def test_set_collection + @model_name.collection = 'foo' + + assert_equal 'foo', @model_name.collection + assert_equal 'foo/track_back', @model_name.partial_path + end + def test_collection assert_equal 'post/track_backs', @model_name.collection end @@ -25,4 +45,14 @@ class NamingTest < ActiveModel::TestCase def test_partial_path assert_equal 'post/track_backs/track_back', @model_name.partial_path end + + def test_should_preserve_custom_collection + @model_name.collection = 'bar' + @model_name.element = 'foo' + + assert_equal 'foo', @model_name.element + assert_equal 'Foo', @model_name.human + assert_equal 'bar', @model_name.collection + assert_equal 'bar/foo', @model_name.partial_path + end end -- cgit v1.2.3 From bea3c26833ad3e1e94f7331e0553a4e2164e7de5 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 6 May 2010 12:35:08 -0300 Subject: Make ActiveResource serialize XML correctly when element_name is set. [#4529] Signed-off-by: Jeremy Kemper --- activemodel/lib/active_model/serializers/xml.rb | 2 +- .../serializeration/xml_serialization_test.rb | 4 +-- activeresource/lib/active_resource/base.rb | 19 +++++++++--- activeresource/test/cases/base_test.rb | 36 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb index df7026b3ec..934af2b8a8 100644 --- a/activemodel/lib/active_model/serializers/xml.rb +++ b/activemodel/lib/active_model/serializers/xml.rb @@ -90,7 +90,7 @@ module ActiveModel @builder = options[:builder] @builder.instruct! unless options[:skip_instruct] - root = (options[:root] || @serializable.class.model_name.singular).to_s + root = (options[:root] || @serializable.class.model_name.element).to_s root = ActiveSupport::XmlMini.rename_key(root, options) args = [root] diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb index 3ba826a8d0..4e8e4efa25 100644 --- a/activemodel/test/cases/serializeration/xml_serialization_test.rb +++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb @@ -37,8 +37,8 @@ class XmlSerializationTest < ActiveModel::TestCase test "should serialize namespaced root" do @xml = Admin::Contact.new(@contact.attributes).to_xml - assert_match %r{^}, @xml - assert_match %r{$}, @xml + assert_match %r{^}, @xml + assert_match %r{$}, @xml end test "should serialize default root with namespace" do diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index ad994214f6..15d77df3b5 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -551,11 +551,22 @@ module ActiveResource @headers ||= {} end - # Do not include any modules in the default element name. This makes it easier to seclude ARes objects - # in a separate namespace without having to set element_name repeatedly. - attr_accessor_with_default(:element_name) { ActiveSupport::Inflector.underscore(to_s.split("::").last) } #:nodoc: + def element_name + model_name.element + end + + def element_name=(value) + model_name.element = value + end + + def collection_name + model_name.collection + end + + def collection_name=(value) + model_name.collection = value + end - attr_accessor_with_default(:collection_name) { ActiveSupport::Inflector.pluralize(element_name) } #:nodoc: attr_accessor_with_default(:primary_key, 'id') #:nodoc: # Gets the \prefix for a resource's nested URL (e.g., prefix/collectionname/1.xml) diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index e5f556962b..5df1f411a4 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -1018,6 +1018,23 @@ class BaseTest < Test::Unit::TestCase assert xml.include?('1') end + def test_to_xml_with_element_name + old_elem_name = Person.element_name + matz = Person.find(1) + Person.element_name = 'ruby_creator' + encode = matz.encode + xml = matz.to_xml + + assert encode, xml + assert xml.include?('') + assert xml.include?('') + assert xml.include?('Matz') + assert xml.include?('1') + assert xml.include?('') + ensure + Person.element_name = old_elem_name + end + def test_to_json Person.include_root_in_json = true Person.format = :json @@ -1033,6 +1050,25 @@ class BaseTest < Test::Unit::TestCase assert_match %r{\}\}\}$}, json end + def test_to_json_with_element_name + old_elem_name = Person.element_name + Person.include_root_in_json = true + Person.format = :json + joe = Person.find(6) + Person.element_name = 'ruby_creator' + encode = joe.encode + json = joe.to_json + Person.format = :xml + + assert encode, json + assert_match %r{^\{"ruby_creator":\{"person":\{}, json + assert_match %r{"id":6}, json + assert_match %r{"name":"Joe"}, json + assert_match %r{\}\}\}$}, json + ensure + Person.element_name = old_elem_name + end + def test_to_param_quacks_like_active_record new_person = Person.new assert_nil new_person.to_param -- cgit v1.2.3 From 6334006b815eadd83575fe6d00e9010838530ee7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 12 May 2010 14:29:39 -0300 Subject: Revert "Refactor of active_model/naming.rb and allow collection and element to be writable" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f7862b2c34b5b298bf7b937c55f0637ebfe43a25. Signed-off-by: José Valim --- activemodel/lib/active_model/naming.rb | 34 +++++----------------------------- activemodel/test/cases/naming_test.rb | 30 ------------------------------ 2 files changed, 5 insertions(+), 59 deletions(-) diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index a860388bae..8cdd3d2fe8 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -3,36 +3,18 @@ require 'active_support/inflector' module ActiveModel class Name < String - attr_reader :singular, :plural, :element + attr_reader :singular, :plural, :element, :collection, :partial_path + alias_method :cache_key, :collection def initialize(klass) super(klass.name) @klass = klass @singular = ActiveSupport::Inflector.underscore(self).tr('/', '_').freeze @plural = ActiveSupport::Inflector.pluralize(@singular).freeze - @collection = nil - self.element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze - end - - def element=(element) - @element = element + @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze @human = ActiveSupport::Inflector.humanize(@element).freeze - @default_collection = nil - @partial_path = nil - end - - def collection - @collection || default_collection - end - alias_method :cache_key, :collection - - def collection=(collection) - @collection = collection - @partial_path = nil - end - - def partial_path - @partial_path ||= "#{collection}/#{@element}" + @collection = ActiveSupport::Inflector.tableize(self).freeze + @partial_path = "#{@collection}/#{@element}".freeze end # Transform the model name into a more humane format, using I18n. By default, @@ -52,12 +34,6 @@ module ActiveModel options.reverse_merge! :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults I18n.translate(defaults.shift, options) end - - private - - def default_collection - @default_collection ||= ActiveSupport::Inflector.tableize(self.sub(/[^:]*$/, @element)).freeze - end end # ActiveModel::Naming is a module that creates a +model_name+ method on your diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index 3918002360..dc39b84ed8 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -18,26 +18,6 @@ class NamingTest < ActiveModel::TestCase assert_equal 'track_back', @model_name.element end - def test_set_element - @model_name.element = 'foo' - - assert_equal 'foo', @model_name.element - assert_equal 'Foo', @model_name.human - assert_equal 'post/foos', @model_name.collection - assert_equal 'post/foos/foo', @model_name.partial_path - end - - def test_human - assert_equal 'Track back', @model_name.human - end - - def test_set_collection - @model_name.collection = 'foo' - - assert_equal 'foo', @model_name.collection - assert_equal 'foo/track_back', @model_name.partial_path - end - def test_collection assert_equal 'post/track_backs', @model_name.collection end @@ -45,14 +25,4 @@ class NamingTest < ActiveModel::TestCase def test_partial_path assert_equal 'post/track_backs/track_back', @model_name.partial_path end - - def test_should_preserve_custom_collection - @model_name.collection = 'bar' - @model_name.element = 'foo' - - assert_equal 'foo', @model_name.element - assert_equal 'Foo', @model_name.human - assert_equal 'bar', @model_name.collection - assert_equal 'bar/foo', @model_name.partial_path - end end -- cgit v1.2.3 From 903637f5f0a1a9789fa12da1519e028b9faa37d8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 12 May 2010 15:31:37 -0300 Subject: Fixes to_json and to_xml for ActiveResource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activeresource/lib/active_resource/base.rb | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 15d77df3b5..ffdb5fb50a 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -552,19 +552,20 @@ module ActiveResource end def element_name - model_name.element + @element_name ||= model_name.element end - def element_name=(value) - model_name.element = value + def element_name=(element_name) + @element_name = element_name + @collection_name ||= model_name.collection.sub(/[^\/]*$/, @element_name.pluralize) end def collection_name - model_name.collection + @collection_name ||= model_name.collection end - def collection_name=(value) - model_name.collection = value + def collection_name=(collection_name) + @collection_name = collection_name end attr_accessor_with_default(:primary_key, 'id') #:nodoc: @@ -1306,6 +1307,14 @@ module ActiveResource end end + def to_json(options={}) + super({ :root => self.class.element_name }.merge(options)) + end + + def to_xml(options={}) + super({ :root => self.class.element_name }.merge(options)) + end + protected def connection(refresh = false) self.class.connection(refresh) -- cgit v1.2.3 From 2203c781a7dfa8b0c8b6c97cd318d941f9fbb26c Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 12 May 2010 23:04:17 +0200 Subject: defines prev_(month|year) in Date and Time to ease transition to 1.9, and deprecates last_(month|year) --- activesupport/CHANGELOG | 2 ++ .../active_support/core_ext/date/calculations.rb | 21 ++++++++++++----- .../active_support/core_ext/time/calculations.rb | 14 ++++++++++-- activesupport/test/core_ext/date_ext_test.rb | 26 ++++++++++++++-------- activesupport/test/core_ext/date_time_ext_test.rb | 8 +++---- activesupport/test/core_ext/time_ext_test.rb | 18 ++++++++++----- .../source/active_support_core_extensions.textile | 22 ++++++++++-------- 7 files changed, 77 insertions(+), 34 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 6146cc6a97..7afd9926b5 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [beta 4/release candidate] (unreleased)* +* Defines prev_(month|year) in Date and Time, and deprecates last_(month|year). [fxn] + * Aliases Date#sunday to Date#end_of_week. [fxn] * Backports Date#>> from 1.9 so that calculations do the right thing around the calendar reform. [fxn] diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 3038729d34..755d96ce91 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -2,6 +2,7 @@ require 'date' require 'active_support/duration' require 'active_support/core_ext/time/zones' require 'active_support/core_ext/object/acts_like' +require 'active_support/deprecation' class Date if RUBY_VERSION < '1.9' @@ -146,20 +147,30 @@ class Date advance(:years => years) end - # Short-hand for years_ago(1) - def last_year - years_ago(1) + def last_year # :nodoc: + ActiveSupport::Deprecation.warn("Date#last_year has been deprecated, please use Date#prev_year instead", caller) + prev_year end + # Shorthand for years_ago(1) + def prev_year + years_ago(1) + end unless method_defined?(:prev_year) + # Short-hand for years_since(1) def next_year years_since(1) end unless method_defined?(:next_year) + def last_month # :nodoc: + ActiveSupport::Deprecation.warn("Date#last_month has been deprecated, please use Date#prev_month instead", caller) + prev_month + end + # Short-hand for months_ago(1) - def last_month + def prev_month months_ago(1) - end + end unless method_defined?(:prev_month) # Short-hand for months_since(1) def next_month diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 2b47ecd543..e27b08ec2e 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -2,6 +2,7 @@ require 'active_support/duration' require 'active_support/core_ext/date/acts_like' require 'active_support/core_ext/date/calculations' require 'active_support/core_ext/date_time/conversions' +require 'active_support/deprecation' class Time COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] @@ -132,8 +133,13 @@ class Time advance(:years => years) end + def last_year # :nodoc: + ActiveSupport::Deprecation.warn("Time#last_year has been deprecated, please use Time#prev_year instead", caller) + prev_year + end + # Short-hand for years_ago(1) - def last_year + def prev_year years_ago(1) end @@ -142,9 +148,13 @@ class Time years_since(1) end + def last_month # :nodoc: + ActiveSupport::Deprecation.warn("Time#last_month has been deprecated, please use Time#prev_month instead", caller) + prev_month + end # Short-hand for months_ago(1) - def last_month + def prev_month months_ago(1) end diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index 2b66fd03d0..1bf118e3b7 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' require 'active_support/time' -class DateExtCalculationsTest < Test::Unit::TestCase +class DateExtCalculationsTest < ActiveSupport::TestCase def test_to_s date = Date.new(2005, 2, 21) assert_equal "2005-02-21", date.to_s @@ -145,16 +145,20 @@ class DateExtCalculationsTest < Test::Unit::TestCase assert_equal Date.new(2005,2,28), Date.new(2004,2,29).years_since(1) # 1 year since leap day end - def test_last_year - assert_equal Date.new(2004,6,5), Date.new(2005,6,5).last_year + def test_last_year_is_deprecated + assert_deprecated { Date.today.last_year } end - def test_last_year_in_leap_years - assert_equal Date.new(1999,2,28), Date.new(2000,2,29).last_year + def test_prev_year + assert_equal Date.new(2004,6,5), Date.new(2005,6,5).prev_year end - def test_last_year_in_calendar_reform - assert_equal Date.new(1582,10,4), Date.new(1583,10,14).last_year + def test_prev_year_in_leap_years + assert_equal Date.new(1999,2,28), Date.new(2000,2,29).prev_year + end + + def test_prev_year_in_calendar_reform + assert_equal Date.new(1582,10,4), Date.new(1583,10,14).prev_year end def test_next_year @@ -225,8 +229,12 @@ class DateExtCalculationsTest < Test::Unit::TestCase assert_equal Date.new(2005, 9, 30), Date.new(2005, 8, 31).next_month end - def test_last_month_on_31st - assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).last_month + def test_last_month_is_deprecated + assert_deprecated { Date.today.last_month } + end + + def test_prev_month_on_31st + assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).prev_month end def test_yesterday_constructor diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index f9af059acd..4780760a19 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -127,8 +127,8 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase assert_equal DateTime.civil(2005,2,28,10), DateTime.civil(2004,2,29,10,0,0).years_since(1) # 1 year since leap day end - def test_last_year - assert_equal DateTime.civil(2004,6,5,10), DateTime.civil(2005,6,5,10,0,0).last_year + def test_prev_year + assert_equal DateTime.civil(2004,6,5,10), DateTime.civil(2005,6,5,10,0,0).prev_year end def test_next_year @@ -200,8 +200,8 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase assert_equal DateTime.civil(2005, 9, 30), DateTime.civil(2005, 8, 31).next_month end - def test_last_month_on_31st - assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).last_month + def test_prev_month_on_31st + assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).prev_month end def test_xmlschema diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 342d6ab577..30ee1d1652 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' require 'active_support/time' -class TimeExtCalculationsTest < Test::Unit::TestCase +class TimeExtCalculationsTest < ActiveSupport::TestCase def test_seconds_since_midnight assert_equal 1,Time.local(2005,1,1,0,0,1).seconds_since_midnight assert_equal 60,Time.local(2005,1,1,0,1,0).seconds_since_midnight @@ -166,8 +166,12 @@ class TimeExtCalculationsTest < Test::Unit::TestCase # assert_equal Time.local(2182,6,5,10), Time.local(2005,6,5,10,0,0).years_since(177) end - def test_last_year - assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).last_year + def test_last_year_is_deprecated + assert_deprecated { Time.now.last_year } + end + + def test_prev_year + assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).prev_year end def test_next_year @@ -615,8 +619,12 @@ class TimeExtCalculationsTest < Test::Unit::TestCase assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month end - def test_last_month_on_31st - assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month + def test_last_month_is_deprecated + assert_deprecated { Time.now.last_month } + end + + def test_prev_month_on_31st + assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).prev_month end def test_xmlschema_is_available diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index b7b5f47eef..fed0c25e8e 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -2660,13 +2660,13 @@ Active Support defines +Date.current+ to be today in the current time zone. That h5. Named dates -h6. +last_year+, +next_year+ +h6. +prev_year+, +next_year+ -The methods +last_year+ and +next_year+ return a date with the same day/month in the last or next year: +In Ruby 1.9 +prev_year+ and +next_year+ return a date with the same day/month in the last or next year: d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.last_year # => Fri, 08 May 2009 +d.prev_year # => Fri, 08 May 2009 d.next_year # => Sun, 08 May 2011 @@ -2674,29 +2674,33 @@ If date is the 29th of February of a leap year, you obtain the 28th: d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000 -d.last_year # => Sun, 28 Feb 1999 +d.prev_year # => Sun, 28 Feb 1999 d.next_year # => Wed, 28 Feb 2001 -h6. +last_month+, +next_month+ +Active Support defines these methods as well for Ruby 1.8. -The methods +last_month+ and +next_month+ return the date with the same day in the last or next month: +h6. +prev_month+, +next_month+ + +In Ruby 1.9 +prev_month+ and +next_month+ return the date with the same day in the last or next month: d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.last_month # => Thu, 08 Apr 2010 +d.prev_month # => Thu, 08 Apr 2010 d.next_month # => Tue, 08 Jun 2010 If such a day does not exist, the last day of the corresponding month is returned: -Date.new(2000, 5, 31).last_month # => Sun, 30 Apr 2000 -Date.new(2000, 3, 31).last_month # => Tue, 29 Feb 2000 +Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000 +Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000 Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000 Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000 +Active Support defines these methods as well for Ruby 1.8. + h6. +beginning_of_week+, +end_of_week+ The methods +beginning_of_week+ and +end_of_week+ return the dates for the beginning and end of week, assuming weeks start on Monday: -- cgit v1.2.3 From 9131a88bb8e82f139ec49b4057fb6065ba0a2c6a Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 11 May 2010 12:28:42 +0200 Subject: validation macros can now be used within an instance --- activemodel/lib/active_model/validations.rb | 9 +-- .../lib/active_model/validations/acceptance.rb | 2 +- .../lib/active_model/validations/confirmation.rb | 2 +- .../lib/active_model/validations/exclusion.rb | 2 +- activemodel/lib/active_model/validations/format.rb | 2 +- .../lib/active_model/validations/helper_methods.rb | 12 ++++ .../lib/active_model/validations/inclusion.rb | 2 +- activemodel/lib/active_model/validations/length.rb | 2 +- .../lib/active_model/validations/numericality.rb | 2 +- .../lib/active_model/validations/presence.rb | 2 +- activemodel/lib/active_model/validations/with.rb | 66 ++++++++++++++++++++++ activemodel/test/cases/validations_test.rb | 13 +++++ activemodel/test/models/automobile.rb | 12 ++++ 13 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 activemodel/lib/active_model/validations/helper_methods.rb create mode 100644 activemodel/test/models/automobile.rb diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 7c705b8899..1e2901633e 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -46,6 +46,9 @@ module ActiveModel included do extend ActiveModel::Translation + + extend HelperMethods; include HelperMethods + define_callbacks :validate, :scope => :name attr_accessor :validation_context @@ -138,12 +141,6 @@ module ActiveModel def attribute_method?(attribute) method_defined?(attribute) end - private - - def _merge_attributes(attr_names) - options = attr_names.extract_options! - options.merge(:attributes => attr_names.flatten) - end end # Returns the Errors object that holds all information about attribute error messages. diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index fbd622eb6d..26b12b504b 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -21,7 +21,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example: # # class Person < ActiveRecord::Base diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 8041d4b61f..51445343f2 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -12,7 +12,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example: # # Model: diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 2f51edfa9a..2ee78f5dd2 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -12,7 +12,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Validates that the value of the specified attribute is not in a particular enumerable object. # # class Person < ActiveRecord::Base diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 9a9e7eca4d..c34c860d4d 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -24,7 +24,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided. # You can require that the attribute matches the regular expression: # diff --git a/activemodel/lib/active_model/validations/helper_methods.rb b/activemodel/lib/active_model/validations/helper_methods.rb new file mode 100644 index 0000000000..4c709b1fa9 --- /dev/null +++ b/activemodel/lib/active_model/validations/helper_methods.rb @@ -0,0 +1,12 @@ +module ActiveModel + module Validations + module HelperMethods + private + + def _merge_attributes(attr_names) + options = attr_names.extract_options! + options.merge(:attributes => attr_names.flatten) + end + end + end +end \ No newline at end of file diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 96dc8b6e15..446646d247 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -12,7 +12,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Validates whether the value of the specified attribute is available in a particular enumerable object. # # class Person < ActiveRecord::Base diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 95da3e93ea..d7218f4f52 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -51,7 +51,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time: # diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index f974999bef..716010e88b 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -70,7 +70,7 @@ module ActiveModel end - module ClassMethods + module HelperMethods # Validates whether the value of the specified attribute is numeric by trying to convert it to # a float with Kernel.Float (if only_integer is false) or applying it to the regular expression # /\A[\+\-]?\d+\Z/ (if only_integer is set to true). diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index 4a71cf79b5..b319f4834b 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -8,7 +8,7 @@ module ActiveModel end end - module ClassMethods + module HelperMethods # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example: # # class Person < ActiveRecord::Base diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 83d3ea80d6..2a2d0d55b4 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -75,5 +75,71 @@ module ActiveModel end end end + + # Passes the record off to the class or classes specified and allows them + # to add errors based on more complex conditions. + # + # class Person + # include ActiveModel::Validations + # + # validates :instance_validations + # + # def instance_validations + # validates_with MyValidator + # end + # end + # + # class MyValidator < ActiveModel::Validator + # def validate(record) + # if some_complex_logic + # record.errors[:base] << "This record is invalid" + # end + # end + # + # private + # def some_complex_logic + # # ... + # end + # end + # + # You may also pass it multiple classes, like so: + # + # class Person + # include ActiveModel::Validations + # + # validates :instance_validations, :on => :create + # + # def instance_validations + # validates_with MyValidator, MyOtherValidator + # end + # end + # + # Standard configuration options (:on, :if and :unless), which are + # available on the class version of validates_with, should instead be + # placed on the validates method as these are applied and tested + # in the callback + # + # If you pass any additional configuration options, they will be passed + # to the class and available as options: + # + # class Person + # include ActiveModel::Validations + # validates_with MyValidator, :my_custom_key => "my custom value" + # end + # + # class MyValidator < ActiveModel::Validator + # def validate(record) + # options[:my_custom_key] # => "my custom value" + # end + # end + # + def validates_with(*args, &block) + options = args.extract_options! + args.each do |klass| + validator = klass.new(options, &block) + validator.setup(self) if validator.respond_to?(:setup) + validator.validate(self) + end + end end end \ No newline at end of file diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 578ffc27dd..aa75b8b0d2 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -4,6 +4,7 @@ require 'cases/helper' require 'models/topic' require 'models/reply' require 'models/custom_reader' +require 'models/automobile' class ValidationsTest < ActiveModel::TestCase @@ -252,4 +253,16 @@ class ValidationsTest < ActiveModel::TestCase Topic.validates_length_of :title, :minimum => 10 assert_equal 10, Topic.validators_on(:title).first.options[:minimum] end + + def test_validations_on_the_instance_level + auto = Automobile.new + + assert auto.invalid? + assert_equal 2, auto.errors.size + + auto.make = 'Toyota' + auto.model = 'Corolla' + + assert auto.valid? + end end diff --git a/activemodel/test/models/automobile.rb b/activemodel/test/models/automobile.rb new file mode 100644 index 0000000000..021ea61c80 --- /dev/null +++ b/activemodel/test/models/automobile.rb @@ -0,0 +1,12 @@ +class Automobile + include ActiveModel::Validations + + validate :validations + + attr_accessor :make, :model + + def validations + validates_presence_of :make + validates_length_of :model, :within => 2..10 + end +end \ No newline at end of file -- cgit v1.2.3 From 92160219a8bf17bd435252304319c094e56e5849 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 11 May 2010 15:36:09 +0200 Subject: =?UTF-8?q?minor=20changes=20to=20instance=20level=20validations?= =?UTF-8?q?=20implementation=20based=20on=20feedback=20from=20Jos=C3=A9=20?= =?UTF-8?q?Valim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- activemodel/lib/active_model/validations.rb | 3 +- .../lib/active_model/validations/helper_methods.rb | 12 ------- activemodel/lib/active_model/validations/with.rb | 37 +++++++--------------- activemodel/lib/active_model/validator.rb | 3 ++ 4 files changed, 17 insertions(+), 38 deletions(-) delete mode 100644 activemodel/lib/active_model/validations/helper_methods.rb diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 1e2901633e..f472f50f9b 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -47,7 +47,8 @@ module ActiveModel included do extend ActiveModel::Translation - extend HelperMethods; include HelperMethods + extend HelperMethods + include HelperMethods define_callbacks :validate, :scope => :name diff --git a/activemodel/lib/active_model/validations/helper_methods.rb b/activemodel/lib/active_model/validations/helper_methods.rb deleted file mode 100644 index 4c709b1fa9..0000000000 --- a/activemodel/lib/active_model/validations/helper_methods.rb +++ /dev/null @@ -1,12 +0,0 @@ -module ActiveModel - module Validations - module HelperMethods - private - - def _merge_attributes(attr_names) - options = attr_names.extract_options! - options.merge(:attributes => attr_names.flatten) - end - end - end -end \ No newline at end of file diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 2a2d0d55b4..6dbde5bfad 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -1,5 +1,13 @@ module ActiveModel module Validations + module HelperMethods + private + def _merge_attributes(attr_names) + options = attr_names.extract_options! + options.merge(:attributes => attr_names.flatten) + end + end + module ClassMethods # Passes the record off to the class or classes specified and allows them @@ -89,18 +97,8 @@ module ActiveModel # end # end # - # class MyValidator < ActiveModel::Validator - # def validate(record) - # if some_complex_logic - # record.errors[:base] << "This record is invalid" - # end - # end - # - # private - # def some_complex_logic - # # ... - # end - # end + # Please consult the class method documentation for more information on + # creating your own validator. # # You may also pass it multiple classes, like so: # @@ -120,24 +118,13 @@ module ActiveModel # in the callback # # If you pass any additional configuration options, they will be passed - # to the class and available as options: - # - # class Person - # include ActiveModel::Validations - # validates_with MyValidator, :my_custom_key => "my custom value" - # end - # - # class MyValidator < ActiveModel::Validator - # def validate(record) - # options[:my_custom_key] # => "my custom value" - # end - # end + # to the class and available as options, please refer to the + # class version of this method for more information # def validates_with(*args, &block) options = args.extract_options! args.each do |klass| validator = klass.new(options, &block) - validator.setup(self) if validator.respond_to?(:setup) validator.validate(self) end end diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index 906d239bcc..56179c1a6c 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -88,6 +88,9 @@ module ActiveModel #:nodoc: # klass.send :attr_accessor, :custom_attribute # end # end + # + # This setup method is only called when used with validation macros or the + # class level validates_with method. # class Validator attr_reader :options -- cgit v1.2.3 From 4a8a62058a81ba9c0ec12adc772adbdca4c900a5 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Thu, 13 May 2010 19:46:33 +1000 Subject: Changed encoding behaviour of mail, so updated tests in actionmailer and bumped mail version to 2.2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionmailer/CHANGELOG | 4 ++++ actionmailer/actionmailer.gemspec | 2 +- actionmailer/test/old_base/mail_service_test.rb | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index 383ad2105d..208299cfd1 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,3 +1,7 @@ +* Changed encoding behaviour of mail, so updated tests in actionmailer and bumped mail version to 2.2.1 [ML] + +* Added ability to pass Proc objects to the defaults hash [ML] + *Rails 3.0.0 [beta 3] (April 13th, 2010)* * Removed all quoting.rb type files from ActionMailer and put Mail 2.2.0 in instead [ML] diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 01a886c5ee..280771e4db 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,6 +20,6 @@ Gem::Specification.new do |s| s.has_rdoc = true s.add_dependency('actionpack', version) - s.add_dependency('mail', '~> 2.2.0') + s.add_dependency('mail', '~> 2.2.1') s.add_dependency('text-format', '~> 1.0.0') end diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index 9da9132fe1..f91e7f893c 100644 --- a/actionmailer/test/old_base/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -674,7 +674,7 @@ The body EOF mail = Mail.new(msg) assert_equal "testing testing \326\244", mail.subject - assert_equal "Subject: testing testing =?UTF-8?Q?_=D6=A4=?=\r\n", mail[:subject].encoded + assert_equal "Subject: =?UTF-8?Q?testing_testing_=D6=A4?=\r\n", mail[:subject].encoded end def test_unquote_7bit_subject @@ -863,7 +863,7 @@ EOF def test_multipart_with_utf8_subject mail = TestMailer.multipart_with_utf8_subject(@recipient) - regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=') + regex = Regexp.escape('Subject: =?UTF-8?Q?Foo_=C3=A1=C3=AB=C3=B4_=C3=AE=C3=BC?=') assert_match(/#{regex}/, mail.encoded) string = "Foo áëô îü" assert_match(string, mail.subject) @@ -871,7 +871,7 @@ EOF def test_implicitly_multipart_with_utf8 mail = TestMailer.implicitly_multipart_with_utf8 - regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=') + regex = Regexp.escape('Subject: =?UTF-8?Q?Foo_=C3=A1=C3=AB=C3=B4_=C3=AE=C3=BC?=') assert_match(/#{regex}/, mail.encoded) string = "Foo áëô îü" assert_match(string, mail.subject) -- cgit v1.2.3 From 0c37bf8f915cad47e8711f525c220ceed95e84ee Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 14 May 2010 14:08:46 -0300 Subject: To allow proper fisting of stack trace Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/relation/query_methods.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 8d8bb659e1..6782554854 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -10,7 +10,7 @@ module ActiveRecord attr_accessor :"#{query_method}_values" next if [:where, :having].include?(query_method) - class_eval <<-CEVAL, __FILE__ + class_eval <<-CEVAL, __FILE__, __LINE__ + 1 def #{query_method}(*args, &block) new_relation = clone new_relation.send(:apply_modules, Module.new(&block)) if block_given? @@ -22,7 +22,7 @@ module ActiveRecord end [:where, :having].each do |query_method| - class_eval <<-CEVAL, __FILE__ + class_eval <<-CEVAL, __FILE__, __LINE__ + 1 def #{query_method}(*args, &block) new_relation = clone new_relation.send(:apply_modules, Module.new(&block)) if block_given? @@ -36,7 +36,7 @@ module ActiveRecord ActiveRecord::Relation::SINGLE_VALUE_METHODS.each do |query_method| attr_accessor :"#{query_method}_value" - class_eval <<-CEVAL, __FILE__ + class_eval <<-CEVAL, __FILE__, __LINE__ + 1 def #{query_method}(value = true, &block) new_relation = clone new_relation.send(:apply_modules, Module.new(&block)) if block_given? -- cgit v1.2.3 From a0621c1086165e4b3cff71b54f08a190851b6314 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Fri, 14 May 2010 15:10:10 -0400 Subject: Better code formatting and proper line numbers for stack traces [#4596 state:resolved] Signed-off-by: Jeremy Kemper --- .../abstract/schema_definitions.rb | 4 +-- .../connection_adapters/mysql_adapter.rb | 30 +++++++++++----------- activeresource/lib/active_resource/schema.rb | 2 +- .../lib/active_support/core_ext/logger.rb | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) 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 e42cd99786..7d58bc2adf 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -494,7 +494,7 @@ module ActiveRecord end %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| - class_eval <<-EOV + class_eval <<-EOV, __FILE__, __LINE__ + 1 def #{column_type}(*args) # def string(*args) options = args.extract_options! # options = args.extract_options! column_names = args # column_names = args @@ -694,7 +694,7 @@ module ActiveRecord # t.string(:goat) # t.string(:goat, :sheep) %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| - class_eval <<-EOV + class_eval <<-EOV, __FILE__, __LINE__ + 1 def #{column_type}(*args) # def string(*args) options = args.extract_options! # options = args.extract_options! column_names = args # column_names = args diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 470ff8d767..ec25bbf18e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -15,26 +15,26 @@ module MysqlCompat #:nodoc: # Ruby driver has a version string and returns null values in each_hash # C driver >= 2.7 returns null values in each_hash if Mysql.const_defined?(:VERSION) && (Mysql::VERSION.is_a?(String) || Mysql::VERSION >= 20700) - target.class_eval <<-'end_eval' - def all_hashes # def all_hashes - rows = [] # rows = [] - each_hash { |row| rows << row } # each_hash { |row| rows << row } - rows # rows - end # end + target.class_eval <<-'end_eval', __FILE__, __LINE__ + 1 + def all_hashes # def all_hashes + rows = [] # rows = [] + each_hash { |row| rows << row } # each_hash { |row| rows << row } + rows # rows + end # end end_eval # adapters before 2.7 don't have a version constant # and don't return null values in each_hash else - target.class_eval <<-'end_eval' - def all_hashes # def all_hashes - rows = [] # rows = [] - all_fields = fetch_fields.inject({}) { |fields, f| # all_fields = fetch_fields.inject({}) { |fields, f| - fields[f.name] = nil; fields # fields[f.name] = nil; fields - } # } - each_hash { |row| rows << all_fields.dup.update(row) } # each_hash { |row| rows << all_fields.dup.update(row) } - rows # rows - end # end + target.class_eval <<-'end_eval', __FILE__, __LINE__ + 1 + def all_hashes # def all_hashes + rows = [] # rows = [] + all_fields = fetch_fields.inject({}) { |fields, f| # all_fields = fetch_fields.inject({}) { |fields, f| + fields[f.name] = nil; fields # fields[f.name] = nil; fields + } # } + each_hash { |row| rows << all_fields.dup.update(row) } # each_hash { |row| rows << all_fields.dup.update(row) } + rows # rows + end # end end_eval end diff --git a/activeresource/lib/active_resource/schema.rb b/activeresource/lib/active_resource/schema.rb index 8368b652c2..5758ac9502 100644 --- a/activeresource/lib/active_resource/schema.rb +++ b/activeresource/lib/active_resource/schema.rb @@ -42,7 +42,7 @@ module ActiveResource # :nodoc: # TODO: We should eventually support all of these: # %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |attr_type| KNOWN_ATTRIBUTE_TYPES.each do |attr_type| - class_eval <<-EOV + class_eval <<-EOV, __FILE__, __LINE__ + 1 def #{attr_type.to_s}(*args) options = args.extract_options! attr_names = args diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb index 22749229a3..c4994ca2ee 100644 --- a/activesupport/lib/active_support/core_ext/logger.rb +++ b/activesupport/lib/active_support/core_ext/logger.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/class/attribute_accessors' # Adds the 'around_level' method to Logger. class Logger #:nodoc: def self.define_around_helper(level) - module_eval <<-end_eval + module_eval <<-end_eval, __FILE__, __LINE__ + 1 def around_#{level}(before_message, after_message, &block) # def around_debug(before_message, after_message, &block) self.#{level}(before_message) # self.debug(before_message) return_value = block.call(self) # return_value = block.call(self) -- cgit v1.2.3 From 35a114a8941cb22d29a536f1215a23a8cf7c4756 Mon Sep 17 00:00:00 2001 From: David Chelimsky + Brian Tatnall Date: Fri, 14 May 2010 16:30:12 -0500 Subject: Modified default_scope to merge with any pre-existing default_scope and added AR::Base::clear_default_scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - clear_default_scope provides users who rely on the old behaviour of each call to default_scope overwriting any previous default scopes an opportunity to maintain that behaviour. [#4583 state:resolved] Signed-off-by: José Valim --- activerecord/lib/active_record/base.rb | 6 ++++- activerecord/test/cases/method_scoping_test.rb | 31 ++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 650a91b385..e7319ce8b9 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1190,7 +1190,11 @@ module ActiveRecord #:nodoc: # default_scope order('last_name, first_name') # end def default_scope(options = {}) - self.default_scoping << construct_finder_arel(options) + self.default_scoping << construct_finder_arel(options, default_scoping.pop) + end + + def clear_default_scope + self.default_scoping.clear end def scoped_methods #:nodoc: diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index a3b496a0e6..3a6354ec6d 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -587,6 +587,18 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase end end +class ClearDefaultScopeTest < ActiveRecord::TestCase + fixtures :developers + + def test_should_clear_default_scope + klass = Class.new(DeveloperCalledDavid) + klass.__send__ :clear_default_scope + expected = Developer.all.collect { |dev| dev.name } + actual = klass.all.collect { |dev| dev.name } + assert_equal expected, actual + end +end + class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts @@ -615,15 +627,30 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scoping_with_inheritance # Inherit a class having a default scope and define a new default scope klass = Class.new(DeveloperOrderedBySalary) - klass.send :default_scope, {} + klass.send :default_scope, :limit => 1 # Scopes added on children should append to parent scope - assert klass.scoped.order_values.blank? + assert_equal 1, klass.scoped.limit_value + assert_equal ['salary DESC'], klass.scoped.order_values # Parent should still have the original scope + assert_equal nil, DeveloperOrderedBySalary.scoped.limit_value assert_equal ['salary DESC'], DeveloperOrderedBySalary.scoped.order_values end + def test_default_scope_called_twice_merges_conditions + Developer.destroy_all + Developer.create!(:name => "David", :salary => 80000) + Developer.create!(:name => "David", :salary => 100000) + Developer.create!(:name => "Brian", :salary => 100000) + + klass = Class.new(Developer) + klass.__send__ :default_scope, :conditions => { :name => "David" } + klass.__send__ :default_scope, :conditions => { :salary => 100000 } + assert_equal 1, klass.count + assert_equal "David", klass.first.name + assert_equal 100000, klass.first.salary + end def test_method_scope expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.salary } received = DeveloperOrderedBySalary.all_ordered_by_name.collect { |dev| dev.salary } -- cgit v1.2.3 From 6e69b42b21d8e76c4d87b6fbc4222f55d3b11a06 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 20 Apr 2010 23:16:18 -0500 Subject: Let label helpers accept blocks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/form_helper.rb | 45 ++++++++++++++-------- .../lib/action_view/helpers/form_tag_helper.rb | 13 +++++-- actionpack/test/template/form_helper_test.rb | 10 +++-- actionpack/test/template/form_tag_helper_test.rb | 9 +++++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 6e26ae6c29..557f8454be 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -573,8 +573,19 @@ module ActionView # label(:post, :privacy, "Public Post", :value => "public") # # => # - def label(object_name, method, text = nil, options = {}) - InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options) + # label(:post, :terms) do + # 'Accept Terms.' + # end + def label(object_name, method, content_or_options_with_block = nil, options = nil, &block) + if block_given? + options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + text = nil + else + text = content_or_options_with_block + end + + options ||= {} + InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options, &block) end # Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object @@ -823,7 +834,7 @@ module ActionView module InstanceTagMethods #:nodoc: extend ActiveSupport::Concern - include Helpers::TagHelper, Helpers::FormTagHelper + include Helpers::CaptureHelper, Context, Helpers::TagHelper, Helpers::FormTagHelper attr_reader :method_name, :object_name @@ -844,7 +855,7 @@ module ActionView end end - def to_label_tag(text = nil, options = {}) + def to_label_tag(text = nil, options = {}, &block) options = options.stringify_keys tag_value = options.delete("value") name_and_id = options.dup @@ -853,19 +864,23 @@ module ActionView options.delete("index") options["for"] ||= name_and_id["id"] - content = if text.blank? - I18n.t("helpers.label.#{object_name}.#{method_name}", :default => "").presence + if block_given? + label_tag(name_and_id["id"], options, &block) else - text.to_s - end + content = if text.blank? + I18n.t("helpers.label.#{object_name}.#{method_name}", :default => "").presence + else + text.to_s + end - content ||= if object && object.class.respond_to?(:human_attribute_name) - object.class.human_attribute_name(method_name) - end + content ||= if object && object.class.respond_to?(:human_attribute_name) + object.class.human_attribute_name(method_name) + end - content ||= method_name.humanize + content ||= method_name.humanize - label_tag(name_and_id["id"], content, options) + label_tag(name_and_id["id"], content, options) + end end def to_input_field_tag(field_type, options = {}) @@ -1137,8 +1152,8 @@ module ActionView @template.fields_for(name, *args, &block) end - def label(method, text = nil, options = {}) - @template.label(@object_name, method, text, objectify_options(options)) + def label(method, text = nil, options = {}, &block) + @template.label(@object_name, method, text, objectify_options(options), &block) end def check_box(method, options = {}, checked_value = "1", unchecked_value = "0") diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index b840f77fb5..9d15805d46 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -142,7 +142,7 @@ module ActionView tag :input, { "type" => "text", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys) end - # Creates a label field + # Creates a label element. Accepts a block. # # ==== Options # * Creates standard HTML attributes for the tag. @@ -156,8 +156,15 @@ module ActionView # # label_tag 'name', nil, :class => 'small_label' # # => - def label_tag(name, text = nil, options = {}) - content_tag :label, text || name.to_s.humanize, { "for" => sanitize_to_id(name) }.update(options.stringify_keys) + def label_tag(name = nil, content_or_options_with_block = nil, options = nil, &block) + if block_given? + options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + end + + options ||= {} + options.stringify_keys! + options["for"] = sanitize_to_id(name) unless name.blank? || options.has_key?("for") + content_tag :label, content_or_options_with_block || name.to_s.humanize, options, &block end # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 2234fbece9..da2adc9869 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -139,6 +139,10 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('', label("post", "title", "The title goes here", :value => "great title")) end + def test_label_with_block + assert_dom_equal('', label(:post, :title) { "The title, please:" }) + end + def test_text_field assert_dom_equal( '', text_field("post", "title") @@ -448,7 +452,7 @@ class FormHelperTest < ActionView::TestCase def test_form_for assert_deprecated do form_for(:post, @post, :html => { :id => 'create-post' }) do |f| - concat f.label(:title) + concat f.label(:title) { "The Title" } concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -458,7 +462,7 @@ class FormHelperTest < ActionView::TestCase expected = "
" + - "" + + "" + "" + "" + "" + @@ -485,7 +489,7 @@ class FormHelperTest < ActionView::TestCase "" + "" + "" + - "" + + "" + "
" assert_dom_equal expected, output_buffer diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index abb0e1df93..1e116c041f 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -288,6 +288,15 @@ class FormTagHelperTest < ActionView::TestCase assert_match VALID_HTML_ID, label_elem['for'] end + def test_label_tag_with_block + assert_dom_equal('', label_tag { "Blocked" }) + end + + def test_label_tag_with_block_and_argument + output = label_tag("clock") { "Grandfather" } + assert_dom_equal('', output) + end + def test_boolean_options assert_dom_equal %(), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes") assert_dom_equal %(), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil) -- cgit v1.2.3 From d18a2742e01d195eb2d228207062aff49f7eb854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 May 2010 09:08:40 +0200 Subject: Improve previous patch a bit [#3645 state:resolved] --- actionpack/lib/action_view/helpers/form_helper.rb | 6 +++--- actionpack/lib/action_view/helpers/form_tag_helper.rb | 9 +++------ actionpack/test/template/form_tag_helper_test.rb | 5 +++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 557f8454be..932e9e2f95 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -576,12 +576,12 @@ module ActionView # label(:post, :terms) do # 'Accept Terms.' # end - def label(object_name, method, content_or_options_with_block = nil, options = nil, &block) + def label(object_name, method, content_or_options = nil, options = nil, &block) if block_given? - options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + options = content_or_options if content_or_options.is_a?(Hash) text = nil else - text = content_or_options_with_block + text = content_or_options end options ||= {} diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 9d15805d46..2a3f826c15 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -156,15 +156,12 @@ module ActionView # # label_tag 'name', nil, :class => 'small_label' # # => - def label_tag(name = nil, content_or_options_with_block = nil, options = nil, &block) - if block_given? - options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - end - + def label_tag(name = nil, content_or_options = nil, options = nil, &block) + options = content_or_options if block_given? && content_or_options.is_a?(Hash) options ||= {} options.stringify_keys! options["for"] = sanitize_to_id(name) unless name.blank? || options.has_key?("for") - content_tag :label, content_or_options_with_block || name.to_s.humanize, options, &block + content_tag :label, content_or_options || name.to_s.humanize, options, &block end # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 1e116c041f..1c095b621e 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -297,6 +297,11 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal('', output) end + def test_label_tag_with_block_and_argument_and_options + output = label_tag("clock", :id => "label_clock") { "Grandfather" } + assert_dom_equal('', output) + end + def test_boolean_options assert_dom_equal %(), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes") assert_dom_equal %(), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil) -- cgit v1.2.3 From 7ffe76046ad142377bf6b286f4477b09513d1e37 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 14 May 2010 09:34:33 -0300 Subject: ActiveResource shouldn't consider modules in the path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4529 state:committed] Signed-off-by: José Valim --- activeresource/lib/active_resource/base.rb | 18 ++---------------- activeresource/test/cases/base_test.rb | 5 +++++ activeresource/test/fixtures/sound.rb | 5 +++++ 3 files changed, 12 insertions(+), 16 deletions(-) create mode 100644 activeresource/test/fixtures/sound.rb diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index ffdb5fb50a..b976844c1c 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -551,22 +551,8 @@ module ActiveResource @headers ||= {} end - def element_name - @element_name ||= model_name.element - end - - def element_name=(element_name) - @element_name = element_name - @collection_name ||= model_name.collection.sub(/[^\/]*$/, @element_name.pluralize) - end - - def collection_name - @collection_name ||= model_name.collection - end - - def collection_name=(collection_name) - @collection_name = collection_name - end + attr_accessor_with_default(:element_name) { model_name.element } #:nodoc: + attr_accessor_with_default(:collection_name) { ActiveSupport::Inflector.pluralize(element_name) } #:nodoc: attr_accessor_with_default(:primary_key, 'id') #:nodoc: diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index 5df1f411a4..4e21e84596 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -2,6 +2,7 @@ require 'abstract_unit' require "fixtures/person" require "fixtures/customer" require "fixtures/street_address" +require "fixtures/sound" require "fixtures/beast" require "fixtures/proxy" require 'active_support/json' @@ -563,6 +564,10 @@ class BaseTest < Test::Unit::TestCase assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg') end + def test_module_element_path + assert_equal '/sounds/1.xml', Asset::Sound.element_path(1) + end + def test_custom_element_path_with_redefined_to_param Person.module_eval do alias_method :original_to_param_element_path, :to_param diff --git a/activeresource/test/fixtures/sound.rb b/activeresource/test/fixtures/sound.rb new file mode 100644 index 0000000000..5c0ef5d55c --- /dev/null +++ b/activeresource/test/fixtures/sound.rb @@ -0,0 +1,5 @@ +module Asset + class Sound < ActiveResource::Base + self.site = "http://37s.sunrise.i:3000" + end +end -- cgit v1.2.3 From 9869ee77cdbf8f0e9c7eb6e33738d0aa8f5dc70a Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Sat, 15 May 2010 09:42:02 +0200 Subject: Accept :alt => nil on image_tag [#4558 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/asset_tag_helper.rb | 2 +- actionpack/test/template/asset_tag_helper_test.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 8731ed0ef3..e1fbc118d5 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -620,7 +620,7 @@ module ActionView options.symbolize_keys! src = options[:src] = path_to_image(source) - options[:alt] ||= File.basename(src, '.*').capitalize + options[:alt] = options.fetch(:alt){ File.basename(src, '.*').capitalize } if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 124bf734ac..b6a6f52876 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -154,7 +154,8 @@ class AssetTagHelperTest < ActionView::TestCase %(image_tag(".pdf.png")) => %(.pdf), %(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(Rails), %(image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) => %(Mouse), - %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(Mouse) + %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(Mouse), + %(image_tag("mouse.png", :alt => nil)) => %() } FaviconLinkToTag = { -- cgit v1.2.3 From bcf5fea5e5a22edd5c7b27c29a53de0a4bedbc27 Mon Sep 17 00:00:00 2001 From: Adrian Sanchez Date: Wed, 5 May 2010 01:39:59 -0500 Subject: Bundler deprecated options in Gemfile with application template using method "gem" [#4534 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/actions.rb | 3 ++- railties/test/generators/actions_test.rb | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index a31932906d..7af329bbf0 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -54,7 +54,8 @@ module Rails name, version = args # Deal with deprecated options - { :env => :only, :lib => :require_as }.each do |old, new| + { :env => :group, :only => :group, + :lib => :require, :require_as => :require }.each do |old, new| next unless options[old] options[new] = options.delete(old) ActiveSupport::Deprecation.warn "#{old.inspect} option in gem is deprecated, use #{new.inspect} instead" diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index e6fab93a87..65fbf61902 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -86,8 +86,13 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com' end - assert_file 'Gemfile', /gem "mislav\-will\-paginate", :require_as => "will\-paginate"/ + assert_deprecated do + action :gem, 'thoughtbot-factory_girl', :require_as => 'factory_girl', :source => 'http://gems.github.com' + end + + assert_file 'Gemfile', /gem "mislav\-will\-paginate", :require => "will\-paginate"/ assert_file 'Gemfile', /source "http:\/\/gems\.github\.com"/ + assert_file 'Gemfile', /gem "thoughtbot-factory_girl", :require => "factory_girl"/ end def test_gem_with_env_should_include_all_dependencies_in_gemfile @@ -97,7 +102,12 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec', :env => %w(development test) end - assert_file 'Gemfile', /gem "rspec", :only => \["development", "test"\]/ + assert_deprecated do + action :gem, 'rspec-rails', :only => %w(development test) + end + + assert_file 'Gemfile', /gem "rspec", :group => \["development", "test"\]/ + assert_file 'Gemfile', /gem "rspec-rails", :group => \["development", "test"\]/ end def test_gem_with_version_should_include_version_in_gemfile -- cgit v1.2.3 From 58adc6737126242d189274d83c50bcade098800a Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 3 May 2010 12:18:25 -0400 Subject: STI should not ignore type condition while applying scopes from parent class scopes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4507 state:resolved] Signed-off-by: José Valim --- activerecord/lib/active_record/named_scope.rb | 6 +----- activerecord/test/cases/named_scope_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index aeed52e72a..3d8f4a030b 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -99,11 +99,7 @@ module ActiveRecord block_given? ? relation.extending(Module.new(&block)) : relation end - singleton_class.instance_eval do - define_method name do |*args| - scopes[name].call(*args) - end - end + singleton_class.send :define_method, name, &scopes[name] end def named_scope(*args, &block) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index e4cafad11e..9db0e7c143 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -142,6 +142,11 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal authors(:david).posts & Post.containing_the_letter_a, authors(:david).posts.containing_the_letter_a end + def test_named_scope_with_STI + assert_equal 3,Post.containing_the_letter_a.count + assert_equal 1,SpecialPost.containing_the_letter_a.count + end + def test_has_many_through_associations_have_access_to_named_scopes assert_not_equal Comment.containing_the_letter_e, authors(:david).comments assert !Comment.containing_the_letter_e.empty? -- cgit v1.2.3 From c77794a924938360bf4e61c9a13cdbe5b58fdf62 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Sat, 15 May 2010 09:12:55 -0300 Subject: Add missing require to with_options [#4601 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/core_ext/object/with_options.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index dd38b7d261..3209cf7f11 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -1,3 +1,5 @@ +require 'active_support/option_merger' + class Object # An elegant way to factor duplication out of options passed to a series of # method calls. Each method called in the block, with the block variable as -- cgit v1.2.3 From 80fc6536bda191731e3963f1539c84a7b0c4e764 Mon Sep 17 00:00:00 2001 From: Jeroen van Dijk + Rodrigo Urubatan Date: Fri, 14 May 2010 23:54:13 +0200 Subject: Added Rake task rails:templates:copy to copy templates for customization [#4574 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/tasks/framework.rake | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 738f7f5301..063a393bfc 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -30,6 +30,28 @@ namespace :rails do generator.apply template, :verbose => false end + namespace :templates do + desc "Copy all the templates from rails to the application directory for customization. Already existing local copies will be overwritten" + task :copy do + generators_lib = File.expand_path("../../generators", __FILE__) + project_templates = "#{Rails.root}/lib/templates" + + default_templates = { "erb" => %w{controller mailer scaffold}, + "rails" => %w{controller helper metal scaffold_controller stylesheets} } + + default_templates.each do |type, names| + local_template_type_dir = File.join(project_templates, type) + FileUtils.mkdir_p local_template_type_dir + + names.each do |name| + dst_name = File.join(local_template_type_dir, name) + src_name = File.join(generators_lib, type, name, "templates") + FileUtils.cp_r src_name, dst_name + end + end + end + end + namespace :update do def invoke_from_app_generator(method) app_generator.invoke(method) -- cgit v1.2.3 From 458f5712dce6d7f23931effe01b7f34b66e4ab3b Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 15 May 2010 03:51:01 -0700 Subject: Remove the need for a special action_mailer.url_for initializer that loads before anything else --- actionmailer/lib/action_mailer/base.rb | 146 +++++++++++++++++------------- actionmailer/lib/action_mailer/railtie.rb | 6 +- 2 files changed, 86 insertions(+), 66 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 88298966eb..e1a480c2fb 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -22,16 +22,16 @@ module ActionMailer #:nodoc: # class Notifier < ActionMailer::Base # default :from => 'no-reply@example.com', # :return_path => 'system@example.com' - # + # # def welcome(recipient) # @account = recipient # mail(:to => recipient.email_address_with_name, # :bcc => ["bcc@example.com", "Order Watcher "]) # end # end - # + # # Within the mailer method, you have access to the following methods: - # + # # * attachments[]= - Allows you to add attachments to your email in an intuitive # manner; attachments['filename.png'] = File.read('path/to/filename.png') # @@ -46,16 +46,16 @@ module ActionMailer #:nodoc: # as headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'}) # # * mail - Allows you to specify your email to send. - # + # # The hash passed to the mail method allows you to specify any header that a Mail::Message # will accept (any valid Email header including optional fields). # # The mail method, if not passed a block, will inspect your views and send all the views with # the same name as the method, so the above action would send the +welcome.text.plain.erb+ view # file as well as the +welcome.text.html.erb+ view file in a +multipart/alternative+ email. - # + # # If you want to explicitly render only certain templates, pass a block: - # + # # mail(:to => user.emai) do |format| # format.text # format.html @@ -79,7 +79,7 @@ module ActionMailer #:nodoc: # # Like Action Controller, each mailer class has a corresponding view directory in which each # method of the class looks for a template with its name. - # + # # To define a template to be used with a mailing, create an .erb file with the same # name as the method in your mailer model. For example, in the mailer defined above, the template at # app/views/notifier/signup_notification.text.plain.erb would be used to generate the email. @@ -104,7 +104,7 @@ module ActionMailer #:nodoc: # # = Generating URLs # - # URLs can be generated in mailer views using url_for or named routes. Unlike controllers from + # URLs can be generated in mailer views using url_for or named routes. Unlike controllers from # Action Pack, the mailer instance doesn't have any context about the incoming request, so you'll need # to provide all of the details needed to generate a URL. # @@ -176,7 +176,7 @@ module ActionMailer #:nodoc: # mail(:to => recipient, :subject => "New account information") # end # end - # + # # Which will (if it had both a welcome.text.plain.erb and welcome.text.html.erb # tempalte in the view directory), send a complete multipart/mixed email with two parts, # the first part being a multipart/alternative with the text and HTML email parts inside, @@ -184,71 +184,71 @@ module ActionMailer #:nodoc: # with the filename +free_book.pdf+. # # = Observing and Intercepting Mails - # + # # Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to # register objects that are called during the mail delivery life cycle. - # + # # An observer object must implement the :delivered_email(message) method which will be # called once for every email sent after the email has been sent. - # + # # An interceptor object must implement the :delivering_email(message) method which will be # called before the email is sent, allowing you to make modifications to the email before it hits # the delivery agents. Your object should make and needed modifications directly to the passed # in Mail::Message instance. # # = Default Hash - # + # # Action Mailer provides some intelligent defaults for your emails, these are usually specified in a # default method inside the class definition: - # + # # class Notifier < ActionMailer::Base # default :sender => 'system@example.com' # end - # + # # You can pass in any header value that a Mail::Message, out of the box, ActionMailer::Base # sets the following: - # + # # * :mime_version => "1.0" # * :charset => "UTF-8", # * :content_type => "text/plain", # * :parts_order => [ "text/plain", "text/enriched", "text/html" ] - # + # # parts_order and charset are not actually valid Mail::Message header fields, # but Action Mailer translates them appropriately and sets the correct values. - # + # # As you can pass in any header, you need to either quote the header as a string, or pass it in as # an underscorised symbol, so the following will work: - # + # # class Notifier < ActionMailer::Base # default 'Content-Transfer-Encoding' => '7bit', # :content_description => 'This is a description' # end - # + # # Finally, Action Mailer also supports passing Proc objects into the default hash, so you # can define methods that evaluate as the message is being generated: - # + # # class Notifier < ActionMailer::Base # default 'X-Special-Header' => Proc.new { my_method } - # + # # private - # + # # def my_method # 'some complex call' # end # end - # + # # Note that the proc is evaluated right at the start of the mail message generation, so if you - # set something in the defaults using a proc, and then set the same thing inside of your + # set something in the defaults using a proc, and then set the same thing inside of your # mailer method, it will get over written by the mailer method. - # + # # = Configuration options # - # These options are specified on the class level, like + # These options are specified on the class level, like # ActionMailer::Base.template_root = "/my/templates" # # * default - You can pass this in at a class level as well as within the class itself as # per the above section. - # + # # * logger - the logger is used for generating information on the mailing run if available. # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. # @@ -288,16 +288,16 @@ module ActionMailer #:nodoc: # * deliveries - Keeps an array of all the emails sent out through the Action Mailer with # delivery_method :test. Most useful for unit and functional testing. # - # * default_charset - This is now deprecated, use the +default+ method above to + # * default_charset - This is now deprecated, use the +default+ method above to # set the default +:charset+. # - # * default_content_type - This is now deprecated, use the +default+ method above + # * default_content_type - This is now deprecated, use the +default+ method above # to set the default +:content_type+. # - # * default_mime_version - This is now deprecated, use the +default+ method above + # * default_mime_version - This is now deprecated, use the +default+ method above # to set the default +:mime_version+. # - # * default_implicit_parts_order - This is now deprecated, use the +default+ method above + # * default_implicit_parts_order - This is now deprecated, use the +default+ method above # to set the default +:parts_order+. Parts Order is used when a message is built implicitly # (i.e. multiple parts are assembled from templates which specify the content type in their # filenames) this variable controls how the parts are ordered. @@ -315,7 +315,7 @@ module ActionMailer #:nodoc: include ActionMailer::OldApi include ActionMailer::DeprecatedApi - + delegate :register_observer, :to => Mail delegate :register_interceptor, :to => Mail @@ -418,17 +418,17 @@ module ActionMailer #:nodoc: # Allows you to pass random and unusual headers to the new +Mail::Message+ object # which will add them to itself. - # + # # headers['X-Special-Domain-Specific-Header'] = "SecretValue" - # + # # You can also pass a hash into headers of header field names and values, which # will then be set on the Mail::Message object: - # + # # headers 'X-Special-Domain-Specific-Header' => "SecretValue", # 'In-Reply-To' => incoming.message_id - # + # # The resulting Mail::Message will have the following in it's header: - # + # # X-Special-Domain-Specific-Header: SecretValue def headers(args=nil) if args @@ -439,45 +439,45 @@ module ActionMailer #:nodoc: end # Allows you to add attachments to an email, like so: - # + # # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg') - # + # # If you do this, then Mail will take the file name and work out the mime type - # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and + # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and # base64 encode the contents of the attachment all for you. - # + # # You can also specify overrides if you want by passing a hash instead of a string: - # + # # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', # :content => File.read('/path/to/filename.jpg')} - # + # # If you want to use a different encoding than Base64, you can pass an encoding in, # but then it is up to you to pass in the content pre-encoded, and don't expect # Mail to know how to decode this data: - # + # # file_content = SpecialEncode(File.read('/path/to/filename.jpg')) # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', # :encoding => 'SpecialEncoding', # :content => file_content } - # + # # You can also search for specific attachments: - # + # # # By Filename # mail.attachments['filename.jpg'] #=> Mail::Part object or nil - # + # # # or by index # mail.attachments[0] #=> Mail::Part (first attachment) - # + # def attachments @_message.attachments end # The main method that creates the message and renders the email templates. There are # two ways to call this method, with a block, or without a block. - # + # # Both methods accept a headers hash. This hash allows you to specify the most used headers # in an email message, these are: - # + # # * :subject - The subject of the message, if this is omitted, Action Mailer will # ask the Rails I18n class for a translated :subject in the scope of # [:actionmailer, mailer_scope, action_name] or if this is missing, will translate the @@ -491,25 +491,25 @@ module ActionMailer #:nodoc: # addresses, or an array of addresses. # * :reply_to - Who to set the Reply-To header of the email to. # * :date - The date to say the email was sent on. - # - # You can set default values for any of the above headers (except :date) by using the default + # + # You can set default values for any of the above headers (except :date) by using the default # class method: - # + # # class Notifier < ActionMailer::Base # self.default :from => 'no-reply@test.lindsaar.net', # :bcc => 'email_logger@test.lindsaar.net', # :reply_to => 'bounces@test.lindsaar.net' # end - # + # # If you need other headers not listed above, use the headers['name'] = value method. # # When a :return_path is specified as header, that value will be used as the 'envelope from' # address for the Mail message. Setting this is useful when you want delivery notifications - # sent to a different address than the one in :from. Mail will actually use the + # sent to a different address than the one in :from. Mail will actually use the # :return_path in preference to the :sender in preference to the :from # field for the 'envelope from' value. # - # If you do not pass a block to the +mail+ method, it will find all templates in the + # If you do not pass a block to the +mail+ method, it will find all templates in the # view paths using by default the mailer name and the method name that it is being # called from, it will then create parts for each of these templates intelligently, # making educated guesses on correct content type and sequence, and return a fully @@ -533,19 +533,19 @@ module ActionMailer #:nodoc: # And now it will look for all templates at "app/views/notifications" with name "another". # # If you do pass a block, you can render specific templates of your choice: - # + # # mail(:to => 'mikel@test.lindsaar.net') do |format| # format.text # format.html # end - # + # # You can even render text directly without using a template: - # + # # mail(:to => 'mikel@test.lindsaar.net') do |format| # format.text { render :text => "Hello Mikel!" } # format.html { render :text => "

Hello Mikel!

" } # end - # + # # Which will render a multipart/alternative email with text/plain and # text/html parts. # @@ -570,7 +570,7 @@ module ActionMailer #:nodoc: default_values = self.class.default.merge(self.class.default) do |k,v| v.respond_to?(:call) ? v.bind(self).call : v end - + # Handle defaults headers = headers.reverse_merge(default_values) headers[:subject] ||= default_i18n_subject @@ -684,6 +684,28 @@ module ActionMailer #:nodoc: container.add_part(part) end + module DeprecatedUrlOptions + def default_url_options + deprecated_url_options + end + + def default_url_options=(val) + deprecated_url_options + end + + def deprecated_url_options + raise "You can no longer call ActionMailer::Base.default_url_options " \ + "directly. You need to set config.action_mailer.default_url_options. " \ + "If you are using ActionMailer standalone, you need to include the " \ + "url_helpers of a router directly." + end + end + + # This module will complain if the user tries to set default_url_options + # directly instead of through the config object. In ActionMailer's Railtie, + # we include the url_helpers of the router, which will override this module + extend DeprecatedUrlOptions + ActiveSupport.run_load_hooks(:action_mailer, self) end end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index 882e078d1b..0730167a3e 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -5,10 +5,6 @@ module ActionMailer class Railtie < Rails::Railtie config.action_mailer = ActiveSupport::OrderedOptions.new - initializer "action_mailer.url_for", :before => :load_environment_config do |app| - ActiveSupport.on_load(:action_mailer) { include app.routes.url_helpers } - end - require "action_mailer/railties/log_subscriber" log_subscriber :action_mailer, ActionMailer::Railties::LogSubscriber.new @@ -18,6 +14,8 @@ module ActionMailer initializer "action_mailer.set_configs" do |app| ActiveSupport.on_load(:action_mailer) do + include app.routes.url_helpers + app.config.action_mailer.each do |k,v| send "#{k}=", v end -- cgit v1.2.3 From 9cfeefb637b603ce41d3019c8baa95ea984620d7 Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 15 May 2010 06:08:55 -0700 Subject: Reorganized initializers a bit to enable better hooks for common cases without the need for Railtie. Specifically, the following hooks were added: * before_configuration: this hook is run immediately after the Application class comes into existence, but before the user has added any configuration. This is the appropriate place to set configuration for your plugin * before_initialize: This is run after all of the user's configuration has completed, but before any initializers have begun (in other words, it runs right after config/environments/{development,production,test}.rb) * after_initialize: This is run after all of the initializers have run. It is an appropriate place for forking in a preforking setup Each of these hooks may be used via ActiveSupport.on_load(name) { }. In all these cases, the context inside the block will be the Application object. This means that for simple cases, you can use these hooks without needing to create a Railtie. --- activerecord/lib/active_record/railtie.rb | 17 +++--- .../lib/active_support/lazy_load_hooks.rb | 18 ++++-- activesupport/test/lazy_load_hooks_test.rb | 67 ++++++++++++++++++++++ railties/guides/source/initialization.textile | 2 - railties/lib/rails/application.rb | 10 ++-- railties/lib/rails/application/bootstrap.rb | 8 +-- railties/lib/rails/application/configuration.rb | 2 +- railties/lib/rails/application/finisher.rb | 6 +- railties/lib/rails/engine.rb | 15 +++-- railties/lib/rails/railtie/configuration.rb | 48 ++++++++++++++-- .../application/initializers/initializers_test.rb | 13 ----- 11 files changed, 154 insertions(+), 52 deletions(-) create mode 100644 activesupport/test/lazy_load_hooks_test.rb diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 898df0a67a..a32fb7d399 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -15,6 +15,12 @@ module ActiveRecord config.generators.orm :active_record, :migration => true, :timestamps => true + config.app_middleware.insert_after "::ActionDispatch::Callbacks", + "ActiveRecord::QueryCache" + + config.app_middleware.insert_after "::ActionDispatch::Callbacks", + "ActiveRecord::ConnectionAdapters::ConnectionManagement" + rake_tasks do load "active_record/railties/databases.rake" end @@ -58,16 +64,9 @@ module ActiveRecord end end - # Setup database middleware after initializers have run - initializer "active_record.initialize_database_middleware", :after => "action_controller.set_configs" do |app| - middleware = app.config.middleware - middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::QueryCache - middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::ConnectionAdapters::ConnectionManagement - end - initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app| - ActiveSupport.on_load(:active_record) do - unless app.config.cache_classes + unless app.config.cache_classes + ActiveSupport.on_load(:active_record) do ActionDispatch::Callbacks.after do ActiveRecord::Base.reset_subclasses ActiveRecord::Base.clear_reloadable_connections! diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index 642a4c105c..3664431a28 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -2,16 +2,26 @@ module ActiveSupport @load_hooks = Hash.new {|h,k| h[k] = [] } @loaded = {} - def self.on_load(name, &block) + def self.on_load(name, options = {}, &block) if base = @loaded[name] - base.instance_eval(&block) + execute_hook(base, options, block) else - @load_hooks[name] << block + @load_hooks[name] << [block, options] + end + end + + def self.execute_hook(base, options, block) + if options[:yield] + block.call(base) + else + base.instance_eval(&block) end end def self.run_load_hooks(name, base = Object) - @load_hooks[name].each { |hook| base.instance_eval(&hook) } @loaded[name] = base + @load_hooks[name].each do |hook, options| + execute_hook(base, options, hook) + end end end \ No newline at end of file diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb new file mode 100644 index 0000000000..58ccc14324 --- /dev/null +++ b/activesupport/test/lazy_load_hooks_test.rb @@ -0,0 +1,67 @@ +require 'abstract_unit' + +class LazyLoadHooksTest < ActiveSupport::TestCase + def test_basic_hook + i = 0 + ActiveSupport.on_load(:basic_hook) { i += 1 } + ActiveSupport.run_load_hooks(:basic_hook) + assert_equal 1, i + end + + def test_hook_registered_after_run + i = 0 + ActiveSupport.run_load_hooks(:registered_after) + assert_equal 0, i + ActiveSupport.on_load(:registered_after) { i += 1 } + assert_equal 1, i + end + + def test_hook_receives_a_context + i = 0 + ActiveSupport.on_load(:contextual) { i += incr } + assert_equal 0, i + ActiveSupport.run_load_hooks(:contextual, FakeContext.new(2)) + assert_equal 2, i + end + + def test_hook_receives_a_context_afterward + i = 0 + ActiveSupport.run_load_hooks(:contextual_after, FakeContext.new(2)) + assert_equal 0, i + ActiveSupport.on_load(:contextual_after) { i += incr } + assert_equal 2, i + end + + def test_hook_with_yield_true + i = 0 + ActiveSupport.on_load(:contextual_yield, :yield => true) do |obj| + i += obj.incr + incr_amt + end + assert_equal 0, i + ActiveSupport.run_load_hooks(:contextual_yield, FakeContext.new(2)) + assert_equal 7, i + end + + def test_hook_with_yield_true_afterward + i = 0 + ActiveSupport.run_load_hooks(:contextual_yield_after, FakeContext.new(2)) + assert_equal 0, i + ActiveSupport.on_load(:contextual_yield_after, :yield => true) do |obj| + i += obj.incr + incr_amt + end + assert_equal 7, i + end + +private + + def incr_amt + 5 + end + + class FakeContext + attr_reader :incr + def initialize(incr) + @incr = incr + end + end +end \ No newline at end of file diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 9ce27fa331..96d6998e1c 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -2379,7 +2379,6 @@ Now that we've referenced that class, it will be required for us. You'll notice * initialize_subscriber * set_clear_dependencies_hook * initialize_dependency_mechanism -* bootstrap_load_path These are all defined using the +initializer+ method: @@ -2930,7 +2929,6 @@ With +@@autoloads+ being * initialize_subscriber * set_clear_dependencies_hook * initialize_dependency_mechanism -* bootstrap_load_path h4. Active Support Initializers diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d39f9a2ae9..9e18dccf69 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -12,7 +12,7 @@ module Rails # points to it. # # In other words, Rails::Application is Singleton and whenever you are accessing - # Rails::Application.config or YourApplication::Application.config, you are actually + # Rails::Application.config or YourApplication::Application.config, you are actually # accessing YourApplication::Application.instance.config. # # == Initialization @@ -40,7 +40,7 @@ module Rails # # The Application is also responsible for building the middleware stack and setting up # both application and engines metals. - # + # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configurable, 'rails/application/configurable' @@ -69,6 +69,8 @@ module Rails raise "You cannot have more than one Rails::Application" if Rails.application super Rails.application = base.instance + + ActiveSupport.run_load_hooks(:before_configuration, base.instance) end def respond_to?(*args) @@ -82,7 +84,7 @@ module Rails end end - delegate :metal_loader, :to => :config + delegate :middleware, :metal_loader, :to => :config def require_environment! environment = paths.config.environment.to_a.first @@ -125,7 +127,7 @@ module Rails end def app - @app ||= middleware.build(routes) + @app ||= config.middleware.build(routes) end def call(env) diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 022e1a91d8..e62eed8a87 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -10,7 +10,8 @@ module Rails require environment if environment end - initializer :load_all_active_support do + initializer :load_active_support do + require 'active_support/dependencies' require "active_support/all" unless config.active_support.bare end @@ -18,7 +19,6 @@ module Rails # Used by Passenger to ensure everything's loaded before forking and # to avoid autoload race conditions in JRuby. initializer :preload_frameworks do - require 'active_support/dependencies' ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks end @@ -66,8 +66,8 @@ module Rails ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end - initializer :bootstrap_load_path do - # This is just an initializer used as hook so all load paths are loaded together + initializer :bootstrap_hook do |app| + ActiveSupport.run_load_hooks(:before_initialize, app) end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 1ad77fdfec..cd77f1adaf 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -33,7 +33,7 @@ module Rails end def middleware - @middleware ||= default_middleware_stack + @middleware ||= app_middleware.merge_into(default_middleware_stack) end def metal_loader diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 94507bb387..03bc270c81 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -35,10 +35,8 @@ module Rails app end - initializer :after_initialize do - config.after_initialize_blocks.each do |block| - block.call(self) - end + initializer :finisher_hook do |app| + ActiveSupport.run_load_hooks(:after_initialize, app) end # Disable dependency loading during request cycle diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index ab0ead65a9..652bd40ee4 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -45,7 +45,7 @@ module Rails # app.middleware.use MyEngine::Middleware # end # end - # + # # == Paths # # Since Rails 3.0, both your Application and Engines do not have hardcoded paths. @@ -125,7 +125,7 @@ module Rails end end - delegate :middleware, :paths, :root, :to => :config + delegate :paths, :root, :to => :config def load_tasks super @@ -133,7 +133,7 @@ module Rails end # Add configured load paths to ruby load paths and remove duplicates. - initializer :set_load_path, :before => :bootstrap_load_path do + initializer :set_load_path, :before => :bootstrap_hook do config.load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end @@ -142,7 +142,10 @@ module Rails # Set the paths from which Rails will automatically load source files, # and the load_once paths. - initializer :set_autoload_paths, :before => :bootstrap_load_path do |app| + # + # This needs to be an initializer, since it needs to run once + # per engine and get the engine as a block parameter + initializer :set_autoload_paths, :before => :bootstrap_hook do |app| ActiveSupport::Dependencies.load_paths.unshift(*config.load_paths) if reloadable?(app) @@ -200,7 +203,9 @@ module Rails end end - initializer :load_app_classes do |app| + # This needs to be an initializer, since it needs to run once + # per engine and get the engine as a block parameter + initializer :load_app_classes, :before => :finisher_hook do |app| next if $rails_rake_task if app.config.cache_classes diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 16eccaccc4..f57d82a3d8 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -3,10 +3,50 @@ require 'rails/configuration' module Rails class Railtie class Configuration + class MiddlewareStackProxy + def initialize + @operations = [] + end + + def insert_before(*args, &block) + @operations << [:insert_before, args, block] + end + + alias insert insert_before + + def insert_after(*args, &block) + @operations << [:insert_after, args, block] + end + + def swap(*args, &block) + @operations << [:swap, args, block] + end + + def use(*args, &block) + @operations << [:use, args, block] + end + + def merge_into(other) + @operations.each do |operation, args, block| + other.send(operation, *args, &block) + end + other + end + end + def initialize @@options ||= {} end + # This allows you to modify the application's middlewares from Engines. + # + # All operations you run on the app_middleware will be replayed on the + # application once it is defined and the default_middlewares are + # created + def app_middleware + @@app_middleware ||= MiddlewareStackProxy.new + end + # Holds generators configuration: # # config.generators do |g| @@ -28,12 +68,8 @@ module Rails end end - def after_initialize_blocks - @@after_initialize_blocks ||= [] - end - - def after_initialize(&blk) - after_initialize_blocks << blk if blk + def after_initialize(&block) + ActiveSupport.on_load(:after_initialize, :yield => true, &block) end def to_prepare_blocks diff --git a/railties/test/application/initializers/initializers_test.rb b/railties/test/application/initializers/initializers_test.rb index 2e6a707175..eca42dada6 100644 --- a/railties/test/application/initializers/initializers_test.rb +++ b/railties/test/application/initializers/initializers_test.rb @@ -28,19 +28,6 @@ module ApplicationTests assert_equal "congratulations", $test_after_initialize_block2 end - test "after_initialize block works correctly when no block is passed" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.after_initialize { $test_after_initialize_block1 = "success" } - config.after_initialize # don't pass a block, this is what we're testing! - config.after_initialize { $test_after_initialize_block2 = "congratulations" } - RUBY - require "#{app_path}/config/environment" - - assert_equal "success", $test_after_initialize_block1 - assert_equal "congratulations", $test_after_initialize_block2 - end - test "after_initialize runs after frameworks have been initialized" do $activerecord_configurations = nil add_to_config <<-RUBY -- cgit v1.2.3 From 6f0ed7aa521e55bb2c12a29b86c0e8e68468cef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 May 2010 15:21:14 +0200 Subject: Update generators test. --- railties/test/generators_test.rb | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 16f8f43b99..74a09d4bde 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -108,21 +108,10 @@ class GeneratorsTest < Rails::Generators::TestCase assert_match /^ fixjour$/, output end - def test_rails_generators_does_not_show_activerecord_info_if_its_the_default - output = capture(:stdout){ Rails::Generators.help } - assert_no_match /ActiveRecord:/, output - assert_no_match /^ active_record:model$/, output - assert_no_match /^ active_record:fixjour$/, output - end - - def test_rails_generators_shows_activerecord_info_if_its_not_the_default - Rails::Generators.options[:rails][:orm] = :data_mapper + def test_rails_generators_does_not_show_activerecord_hooks output = capture(:stdout){ Rails::Generators.help } assert_match /ActiveRecord:/, output - assert_match /^ active_record:model$/, output assert_match /^ active_record:fixjour$/, output - ensure - Rails::Generators.options[:rails][:orm] = :active_record end def test_no_color_sets_proper_shell -- cgit v1.2.3 From cdf700147c5b3ec5e4d1e7de1c2d08134568c2d1 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Sat, 15 May 2010 13:26:33 +0200 Subject: fix assert_select messages to its declaration behaviour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_dispatch/testing/assertions/selector.rb | 16 +++++++++++----- actionpack/test/controller/assert_select_test.rb | 16 +++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index a6b1126e2b..9deabf5b3c 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -298,10 +298,14 @@ module ActionDispatch # found one but expecting two. message ||= content_mismatch if matches.empty? # Test minimum/maximum occurrence. - min, max = equals[:minimum], equals[:maximum] - message = message || %(Expected #{count_description(min, max)} matching "#{selector.to_s}", found #{matches.size}.) - assert matches.size >= min, message if min - assert matches.size <= max, message if max + min, max, count = equals[:minimum], equals[:maximum], equals[:count] + message = message || %(Expected #{count_description(min, max, count)} matching "#{selector.to_s}", found #{matches.size}.) + if count + assert matches.size == count, message + else + assert matches.size >= min, message if min + assert matches.size <= max, message if max + end # If a block is given call that block. Set @selected to allow # nested assert_select, which can be nested several levels deep. @@ -318,11 +322,13 @@ module ActionDispatch matches end - def count_description(min, max) #:nodoc: + def count_description(min, max, count) #:nodoc: pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')} if min && max && (max != min) "between #{min} and #{max} elements" + elsif min && max && max == min && count + "exactly #{count} #{pluralize['element', min]}" elsif min && !(min == 1 && max == 1) "at least #{min} #{pluralize['element', min]}" elsif max diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 4ef6fa4000..f1254abcf7 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -80,10 +80,15 @@ class AssertSelectTest < ActionController::TestCase def test_assert_select render_html %Q{
} assert_select "div", 2 - assert_failure(/Expected at least 3 elements matching \"div\", found 2/) { assert_select "div", 3 } assert_failure(/Expected at least 1 element matching \"p\", found 0/) { assert_select "p" } end + def test_equality_integer + render_html %Q{
} + assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) { assert_select "div", 3 } + assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", 0 } + end + def test_equality_true_false render_html %Q{
} assert_nothing_raised { assert_select "div" } @@ -94,6 +99,11 @@ class AssertSelectTest < ActionController::TestCase assert_nothing_raised { assert_select "p", false } end + def test_equality_false_message + render_html %Q{
} + assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", false } + end + def test_equality_string_and_regexp render_html %Q{
foo
foo
} assert_nothing_raised { assert_select "div", "foo" } @@ -128,7 +138,7 @@ class AssertSelectTest < ActionController::TestCase def test_counts render_html %Q{
foo
foo
} assert_nothing_raised { assert_select "div", 2 } - assert_failure(/Expected at least 3 elements matching \"div\", found 2/) do + assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do assert_select "div", 3 end assert_nothing_raised { assert_select "div", 1..2 } @@ -136,7 +146,7 @@ class AssertSelectTest < ActionController::TestCase assert_select "div", 3..4 end assert_nothing_raised { assert_select "div", :count=>2 } - assert_failure(/Expected at least 3 elements matching \"div\", found 2/) do + assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do assert_select "div", :count=>3 end assert_nothing_raised { assert_select "div", :minimum=>1 } -- cgit v1.2.3 From e807476d31fd15fbf8808d739b0afada4faeece9 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 15 Apr 2010 18:59:24 +0200 Subject: added convenience methods #notice and #alert to flash.now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/middleware/flash.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 99b36366d6..adde183cdb 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -49,6 +49,16 @@ module ActionDispatch def [](k) @flash[k] end + + # Convenience accessor for flash.now[:alert]= + def alert=(message) + self[:alert] = message + end + + # Convenience accessor for flash.now[:notice]= + def notice=(message) + self[:notice] = message + end end class FlashHash < Hash -- cgit v1.2.3 From 2d84f24af5cb0854a316929fa0d0720773be2162 Mon Sep 17 00:00:00 2001 From: Anil Wadghule Date: Sat, 15 May 2010 20:18:31 +0530 Subject: Add tests for convenience methods #notice and #alert to flash.now [#4369 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/controller/flash_test.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 3c651ebebc..c662ce264b 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -81,6 +81,16 @@ class FlashTest < ActionController::TestCase redirect_to '/somewhere', :notice => "Good luck in the somewheres!" end + def render_with_flash_now_alert + flash.now.alert = "Beware the nowheres now!" + render :inline => "hello" + end + + def render_with_flash_now_notice + flash.now.notice = "Good luck in the somewheres now!" + render :inline => "hello" + end + def redirect_with_other_flashes redirect_to '/wonderland', :flash => { :joyride => "Horses!" } end @@ -183,6 +193,16 @@ class FlashTest < ActionController::TestCase assert_equal "Good luck in the somewheres!", @controller.send(:flash)[:notice] end + def test_render_with_flash_now_alert + get :render_with_flash_now_alert + assert_equal "Beware the nowheres now!", @controller.send(:flash)[:alert] + end + + def test_render_with_flash_now_notice + get :render_with_flash_now_notice + assert_equal "Good luck in the somewheres now!", @controller.send(:flash)[:notice] + end + def test_redirect_to_with_other_flashes get :redirect_with_other_flashes assert_equal "Horses!", @controller.send(:flash)[:joyride] -- cgit v1.2.3 From 3436fdfc12d58925e3d981e0afa61084ea34736c Mon Sep 17 00:00:00 2001 From: Diego Algorta Date: Sat, 15 May 2010 12:33:18 -0300 Subject: Fix for get_ids when including a belongs_to association on a has_many association [#2896 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations.rb | 2 +- activerecord/test/cases/associations/has_many_associations_test.rb | 4 ++++ activerecord/test/models/post.rb | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 0a3c7c6a60..634d4a181a 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1398,7 +1398,7 @@ module ActiveRecord primary_key = reflection.source_reflection.primary_key_name send(through.name).select("DISTINCT #{through.quoted_table_name}.#{primary_key}").map!(&:"#{primary_key}") else - send(reflection.name).select("#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map!(&:id) + send(reflection.name).select("#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").except(:includes).map!(&:id) end end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index b55b08bf9d..6e47967696 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -900,6 +900,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients.loaded? end + def test_get_ids_ignores_include_option + assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids + end + def test_get_ids_for_unloaded_finder_sql_associations_loads_them company = companies(:first_firm) assert !company.clients_using_sql.loaded? diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index d092c4bf09..dd06822cfd 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -69,6 +69,7 @@ class Post < ActiveRecord::Base has_many :authors, :through => :categorizations has_many :readers + has_many :readers_with_person, :include => :person, :class_name => "Reader" has_many :people, :through => :readers has_many :people_with_callbacks, :source=>:person, :through => :readers, :before_add => lambda {|owner, reader| log(:added, :before, reader.first_name) }, -- cgit v1.2.3 From fa99de0bd054576336c940ca78f3d1b35b6e490e Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Sat, 15 May 2010 13:25:48 +0200 Subject: partial counters with :as [#2804 state:resolved] Signed-off-by: Jeremy Kemper --- actionpack/lib/action_view/render/partials.rb | 1 + actionpack/test/controller/render_test.rb | 9 +++++++++ actionpack/test/fixtures/test/_customer_counter_with_as.erb | 1 + 3 files changed, 11 insertions(+) create mode 100644 actionpack/test/fixtures/test/_customer_counter_with_as.erb diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 974345633c..6160a95e20 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -248,6 +248,7 @@ module ActionView @collection.each do |object| locals[counter_name] += 1 + locals["#{as.to_s}_counter".to_sym] = locals[counter_name] locals[as] = object segments << template.render(@view, locals) diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 2f3997518f..180d5e1a65 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -547,6 +547,10 @@ class TestController < ActionController::Base render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] end + def partial_collection_with_as_and_counter + render :partial => "customer_counter_with_as", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :client + end + def partial_collection_with_locals render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } end @@ -1242,6 +1246,11 @@ class RenderTest < ActionController::TestCase assert_equal "david0mary1", @response.body end + def test_partial_collection_with_as_and_counter + get :partial_collection_with_as_and_counter + assert_equal "david0mary1", @response.body + end + def test_partial_collection_with_locals get :partial_collection_with_locals assert_equal "Bonjour: davidBonjour: mary", @response.body diff --git a/actionpack/test/fixtures/test/_customer_counter_with_as.erb b/actionpack/test/fixtures/test/_customer_counter_with_as.erb new file mode 100644 index 0000000000..1241eb604d --- /dev/null +++ b/actionpack/test/fixtures/test/_customer_counter_with_as.erb @@ -0,0 +1 @@ +<%= client.name %><%= client_counter %> \ No newline at end of file -- cgit v1.2.3 From 47c9a355062888feb2c7ea7c794e914a9b78f50c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 15 May 2010 18:53:47 +0100 Subject: Reset quoted_table_name after set_table_name [#4568 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/base_test.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e7319ce8b9..04c474c9a1 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -668,7 +668,6 @@ module ActiveRecord #:nodoc: name = "#{full_table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}" end - @quoted_table_name = nil set_table_name(name) name end @@ -702,6 +701,7 @@ module ActiveRecord #:nodoc: # set_table_name "project" # end def set_table_name(value = nil, &block) + @quoted_table_name = nil define_attr_method :table_name, value, &block end alias :table_name= :set_table_name diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index bbc4e543d5..b7ae619787 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1793,6 +1793,18 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "bar", k.table_name end + def test_quoted_table_name_after_set_table_name + klass = Class.new(ActiveRecord::Base) + + klass.set_table_name "foo" + assert_equal "foo", klass.table_name + assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name + + klass.set_table_name "bar" + assert_equal "bar", klass.table_name + assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name + end + def test_set_table_name_with_block k = Class.new( ActiveRecord::Base ) k.set_table_name { "ks" } -- cgit v1.2.3 From bc1c8d58ec45593acba614d1d0fecb49adef08ff Mon Sep 17 00:00:00 2001 From: Jeroen van Dijk Date: Sat, 15 May 2010 19:43:45 +0200 Subject: Make ActiveModel::Errors#add_on_blank and #add_on_empty accept an options hash and make various Validators pass their (filtered) options. This makes it possible to pass additional options through Validators to message generation. E.g. plugin authors want to add validates_presence_of :foo, :format => "some format". Also, cleanup the :default vs :message options confusion in ActiveModel validation message generation. Also, deprecate ActiveModel::Errors#add_on_blank(attributes, custom_message) in favor of ActiveModel::Errors#add_on_blank(attributes, options). Original patch by Sven Fuchs, some minor changes and has been changed to be applicable to master again [#4057 state:committed] Signed-off-by: Jeremy Kemper --- activemodel/lib/active_model/errors.rb | 54 ++++++++++---- .../lib/active_model/validations/acceptance.rb | 2 +- .../lib/active_model/validations/confirmation.rb | 2 +- .../lib/active_model/validations/exclusion.rb | 2 +- activemodel/lib/active_model/validations/format.rb | 4 +- .../lib/active_model/validations/inclusion.rb | 2 +- activemodel/lib/active_model/validations/length.rb | 4 +- .../lib/active_model/validations/numericality.rb | 8 +-- .../lib/active_model/validations/presence.rb | 2 +- .../i18n_generate_message_validation_test.rb | 82 +++++++++++----------- .../test/cases/validations/i18n_validation_test.rb | 64 ++++++++--------- .../lib/active_record/validations/associated.rb | 2 +- .../lib/active_record/validations/uniqueness.rb | 2 +- .../i18n_generate_message_validation_test.rb | 12 ++-- .../test/cases/validations/i18n_validation_test.rb | 8 +-- 15 files changed, 139 insertions(+), 111 deletions(-) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 14afc5265f..b18b62f926 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -179,25 +179,45 @@ module ActiveModel # If +message+ is a Proc, it will be called, allowing for things like Time.now to be used within an error def add(attribute, message = nil, options = {}) message ||= :invalid - message = generate_message(attribute, message, options) if message.is_a?(Symbol) + + reserved = [:minimum, :maximum, :is, :within , :in, :allow_nil, :allow_blank, :case_sensitive, + :too_long, :too_short, :wrong_length, :on, :if, :unless , :tokenizer, :invalid, + :only_integer, :odd, :even, :less_than, :with, :accept] + + message = generate_message(attribute, message, options.except(*reserved)) if message.is_a?(Symbol) + message = message.call if message.is_a?(Proc) self[attribute] << message end # Will add an error message to each of the attributes in +attributes+ that is empty. - def add_on_empty(attributes, custom_message = nil) + def add_on_empty(attributes, options = {}) + if options && !options.is_a?(Hash) + options = { :message => options } + ActiveSupport::Deprecation.warn \ + "ActiveModel::Errors#add_on_empty(attributes, custom_message) has been deprecated.\n" + + "Instead of passing a custom_message pass an options Hash { :message => custom_message }." + end + [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) is_empty = value.respond_to?(:empty?) ? value.empty? : false - add(attribute, :empty, :default => custom_message) unless !value.nil? && !is_empty + add(attribute, :empty, options) if value.nil? || is_empty end end # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). - def add_on_blank(attributes, custom_message = nil) + def add_on_blank(attributes, options = {}) + if options && !options.is_a?(Hash) + options = { :message => options } + ActiveSupport::Deprecation.warn \ + "ActiveModel::Errors#add_on_blank(attributes, custom_message) has been deprecated.\n" + + "Instead of passing a custom_message pass an options Hash { :message => custom_message }." + end + [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) - add(attribute, :blank, :default => custom_message) if value.blank? + add(attribute, :blank, options) if value.blank? end end @@ -254,18 +274,26 @@ module ActiveModel #
  • errors.attributes.title.blank
  • #
  • errors.messages.blank
  • # - def generate_message(attribute, message = :invalid, options = {}) - message, options[:default] = options[:default], message if options[:default].is_a?(Symbol) + + def generate_message(attribute, type = :invalid, options = {}) + type = options.delete(:message) if options[:message].is_a?(Symbol) + + if options[:default] + ActiveSupport::Deprecation.warn \ + "ActiveModel::Errors#generate_message(attributes, custom_message) has been deprecated.\n" + + "Use ActiveModel::Errors#generate_message(attributes, :message => 'your message') instead." + options[:message] = options.delete(:default) + end defaults = @base.class.lookup_ancestors.map do |klass| - [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{message}", - :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{message}" ] + [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{type}", + :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{type}" ] end - defaults << options.delete(:default) - defaults << :"#{@base.class.i18n_scope}.errors.messages.#{message}" - defaults << :"errors.attributes.#{attribute}.#{message}" - defaults << :"errors.messages.#{message}" + defaults << options.delete(:message) + defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" + defaults << :"errors.attributes.#{attribute}.#{type}" + defaults << :"errors.messages.#{type}" defaults.compact! defaults.flatten! diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index 26b12b504b..ced083b312 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -7,7 +7,7 @@ module ActiveModel def validate_each(record, attribute, value) unless value == options[:accept] - record.errors.add(attribute, :accepted, :default => options[:message]) + record.errors.add(attribute, :accepted, options) end end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 51445343f2..66bce0d2de 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -4,7 +4,7 @@ module ActiveModel def validate_each(record, attribute, value) confirmed = record.send(:"#{attribute}_confirmation") return if confirmed.nil? || value == confirmed - record.errors.add(attribute, :confirmation, :default => options[:message]) + record.errors.add(attribute, :confirmation, options) end def setup(klass) diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 2ee78f5dd2..da4c84fbd6 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return unless options[:in].include?(value) - record.errors.add(attribute, :exclusion, :default => options[:message], :value => value) + record.errors.add(attribute, :exclusion, options.merge(:value => value)) end end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index c34c860d4d..2667baa5a0 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -3,9 +3,9 @@ module ActiveModel class FormatValidator < EachValidator def validate_each(record, attribute, value) if options[:with] && value.to_s !~ options[:with] - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) + record.errors.add(attribute, :invalid, options.merge(:value => value)) elsif options[:without] && value.to_s =~ options[:without] - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) + record.errors.add(attribute, :invalid, options.merge(:value => value)) end end diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 446646d247..0ddf191b4f 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return if options[:in].include?(value) - record.errors.add(attribute, :inclusion, :default => options[:message], :value => value) + record.errors.add(attribute, :inclusion, options.merge(:value => value)) end end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index d7218f4f52..9b671f58de 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -37,7 +37,7 @@ module ActiveModel CHECKS.each do |key, validity_check| next unless check_value = options[key] - custom_message = options[:message] || options[MESSAGES[key]] + options[:message] ||= options[MESSAGES[key]] if options[MESSAGES[key]] valid_value = if key == :maximum value.nil? || value.size.send(validity_check, check_value) @@ -46,7 +46,7 @@ module ActiveModel end next if valid_value - record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) + record.errors.add(attribute, MESSAGES[key], options.merge(:count => check_value)) end end end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 716010e88b..d407258442 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -26,13 +26,13 @@ module ActiveModel return if options[:allow_nil] && raw_value.nil? unless value = parse_raw_value_as_a_number(raw_value) - record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message]) + record.errors.add(attr_name, :not_a_number, options.merge(:value => raw_value)) return end if options[:only_integer] unless value = parse_raw_value_as_an_integer(raw_value) - record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message]) + record.errors.add(attr_name, :not_an_integer, options.merge(:value => raw_value)) return end end @@ -41,14 +41,14 @@ module ActiveModel case option when :odd, :even unless value.to_i.send(CHECKS[option]) - record.errors.add(attr_name, option, :value => value, :default => options[:message]) + record.errors.add(attr_name, option, options.merge(:value => value)) end else option_value = option_value.call(record) if option_value.is_a?(Proc) option_value = record.send(option_value) if option_value.is_a?(Symbol) unless value.send(CHECKS[option], option_value) - record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value) + record.errors.add(attr_name, option, options.merge(:value => value, :count => option_value)) end end end diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index b319f4834b..2826a10ffe 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -4,7 +4,7 @@ module ActiveModel module Validations class PresenceValidator < EachValidator def validate(record) - record.errors.add_on_blank(attributes, options[:message]) + record.errors.add_on_blank(attributes, options) end end diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index 58a8d179ad..0679e67f84 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -8,131 +8,131 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase @person = Person.new end - # validates_inclusion_of: generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) + # validates_inclusion_of: generate_message(attr_name, :inclusion, :message => custom_message, :value => value) def test_generate_message_inclusion_with_default_message - assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, :default => nil, :value => 'title') + assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, :value => 'title') end def test_generate_message_inclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :message => 'custom message %{value}', :value => 'title') end - # validates_exclusion_of: generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) + # validates_exclusion_of: generate_message(attr_name, :exclusion, :message => custom_message, :value => value) def test_generate_message_exclusion_with_default_message - assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, :default => nil, :value => 'title') + assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, :value => 'title') end def test_generate_message_exclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :message => 'custom message %{value}', :value => 'title') end - # validates_format_of: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + # validates_format_of: generate_message(attr_name, :invalid, :message => custom_message, :value => value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, :default => nil, :value => 'title') + assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, :value => 'title') end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') end - # validates_confirmation_of: generate_message(attr_name, :confirmation, :default => configuration[:message]) + # validates_confirmation_of: generate_message(attr_name, :confirmation, :message => custom_message) def test_generate_message_confirmation_with_default_message - assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation, :default => nil) + assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation) end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :message => 'custom message') end - # validates_acceptance_of: generate_message(attr_name, :accepted, :default => configuration[:message]) + # validates_acceptance_of: generate_message(attr_name, :accepted, :message => custom_message) def test_generate_message_accepted_with_default_message - assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted, :default => nil) + assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted) end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :message => 'custom message') end - # add_on_empty: generate_message(attr, :empty, :default => custom_message) + # add_on_empty: generate_message(attr, :empty, :message => custom_message) def test_generate_message_empty_with_default_message - assert_equal "can't be empty", @person.errors.generate_message(:title, :empty, :default => nil) + assert_equal "can't be empty", @person.errors.generate_message(:title, :empty) end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :message => 'custom message') end - # add_on_blank: generate_message(attr, :blank, :default => custom_message) + # add_on_blank: generate_message(attr, :blank, :message => custom_message) def test_generate_message_blank_with_default_message - assert_equal "can't be blank", @person.errors.generate_message(:title, :blank, :default => nil) + assert_equal "can't be blank", @person.errors.generate_message(:title, :blank) end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :message => 'custom message') end - # validates_length_of: generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) + # validates_length_of: generate_message(attr, :too_long, :message => custom_message, :count => option_value.end) def test_generate_message_too_long_with_default_message - assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :default => nil, :count => 10) + assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :count => 10) end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :default => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :message => 'custom message %{count}', :count => 10) end - # validates_length_of: generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin) + # validates_length_of: generate_message(attr, :too_short, :default => custom_message, :count => option_value.begin) def test_generate_message_too_short_with_default_message - assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :default => nil, :count => 10) + assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :count => 10) end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :default => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :message => 'custom message %{count}', :count => 10) end - # validates_length_of: generate_message(attr, key, :default => custom_message, :count => option_value) + # validates_length_of: generate_message(attr, :wrong_length, :message => custom_message, :count => option_value) def test_generate_message_wrong_length_with_default_message - assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :default => nil, :count => 10) + assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :count => 10) end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :default => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :message => 'custom message %{count}', :count => 10) end - # validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) + # validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :message => custom_message) def test_generate_message_not_a_number_with_default_message - assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, :default => nil, :value => 'title') + assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, :value => 'title') end def test_generate_message_not_a_number_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :message => 'custom message %{value}', :value => 'title') end - # validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => configuration[:message]) + # validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => custom_message) def test_generate_message_greater_than_with_default_message - assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, :default => nil, :value => 'title', :count => 10) + assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, :value => 'title', :count => 10) end def test_generate_message_greater_than_or_equal_to_with_default_message - assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, :default => nil, :value => 'title', :count => 10) + assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, :value => 'title', :count => 10) end def test_generate_message_equal_to_with_default_message - assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, :default => nil, :value => 'title', :count => 10) + assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, :value => 'title', :count => 10) end def test_generate_message_less_than_with_default_message - assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, :default => nil, :value => 'title', :count => 10) + assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, :value => 'title', :count => 10) end def test_generate_message_less_than_or_equal_to_with_default_message - assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, :default => nil, :value => 'title', :count => 10) + assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, :value => 'title', :count => 10) end def test_generate_message_odd_with_default_message - assert_equal "must be odd", @person.errors.generate_message(:title, :odd, :default => nil, :value => 'title', :count => 10) + assert_equal "must be odd", @person.errors.generate_message(:title, :odd, :value => 'title', :count => 10) end def test_generate_message_even_with_default_message - assert_equal "must be even", @person.errors.generate_message(:title, :even, :default => nil, :value => 'title', :count => 10) + assert_equal "must be even", @person.errors.generate_message(:title, :even, :value => 'title', :count => 10) end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 547d80f46e..eff2b78e74 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -22,23 +22,23 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_add_on_empty_generates_message - @person.errors.expects(:generate_message).with(:title, :empty, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :empty, {}) @person.errors.add_on_empty :title end def test_errors_add_on_empty_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'}) - @person.errors.add_on_empty :title, 'custom' + @person.errors.expects(:generate_message).with(:title, :empty, {:message => 'custom'}) + @person.errors.add_on_empty :title, :message => 'custom' end def test_errors_add_on_blank_generates_message - @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :blank, {}) @person.errors.add_on_blank :title end def test_errors_add_on_blank_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) - @person.errors.add_on_blank :title, 'custom' + @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'}) + @person.errors.add_on_blank :title, :message => 'custom' end def test_full_message_encoding @@ -66,14 +66,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_confirmation_of_generates_message Person.validates_confirmation_of :title @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :confirmation, {}) @person.valid? end def test_validates_confirmation_of_generates_message_with_custom_default_message Person.validates_confirmation_of :title, :message => 'custom' @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :confirmation, {:message => 'custom'}) @person.valid? end @@ -81,13 +81,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_acceptance_of_generates_message Person.validates_acceptance_of :title, :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :accepted, {}) @person.valid? end def test_validates_acceptance_of_generates_message_with_custom_default_message Person.validates_acceptance_of :title, :message => 'custom', :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :accepted, {:message => 'custom'}) @person.valid? end @@ -95,13 +95,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_presence_of_generates_message Person.validates_presence_of :title - @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :blank, {}) @person.valid? end def test_validates_presence_of_generates_message_with_custom_default_message Person.validates_presence_of :title, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'}) @person.valid? end @@ -109,27 +109,27 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_length_of_within_generates_message_with_title_too_short Person.validates_length_of :title, :within => 3..5 - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil}) + @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message Person.validates_length_of :title, :within => 3..5, :too_short => 'custom' - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :message => 'custom'}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_long Person.validates_length_of :title, :within => 3..5 @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) + @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message Person.validates_length_of :title, :within => 3..5, :too_long => 'custom' @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :message => 'custom'}) @person.valid? end @@ -137,13 +137,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_length_of_is_generates_message Person.validates_length_of :title, :is => 5 - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil}) + @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5}) @person.valid? end def test_validates_length_of_is_generates_message_with_custom_default_message Person.validates_length_of :title, :is => 5, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :message => 'custom'}) @person.valid? end @@ -152,14 +152,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_format_of_generates_message Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil}) + @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x'}) @person.valid? end def test_validates_format_of_generates_message_with_custom_default_message Person.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom' @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :message => 'custom'}) @person.valid? end @@ -168,14 +168,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_inclusion_of_generates_message Person.validates_inclusion_of :title, :in => %w(a b c) @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil}) + @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z'}) @person.valid? end def test_validates_inclusion_of_generates_message_with_custom_default_message Person.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom' @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :message => 'custom'}) @person.valid? end @@ -184,14 +184,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_exclusion_of_generates_message Person.validates_exclusion_of :title, :in => %w(a b c) @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil}) + @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a'}) @person.valid? end def test_validates_exclusion_of_generates_message_with_custom_default_message Person.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom' @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :message => 'custom'}) @person.valid? end @@ -200,14 +200,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_generates_message Person.validates_numericality_of :title @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil}) + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a'}) @person.valid? end def test_validates_numericality_of_generates_message_with_custom_default_message Person.validates_numericality_of :title, :message => 'custom' @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :message => 'custom'}) @person.valid? end @@ -216,14 +216,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_only_integer_generates_message Person.validates_numericality_of :title, :only_integer => true @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil}) + @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0'}) @person.valid? end def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :message => 'custom' @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :message => 'custom'}) @person.valid? end @@ -232,14 +232,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_odd_generates_message Person.validates_numericality_of :title, :only_integer => true, :odd => true @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil}) + @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0}) @person.valid? end def test_validates_numericality_of_odd_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom' @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :message => 'custom'}) @person.valid? end @@ -248,14 +248,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_less_than_generates_message Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil}) + @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0}) @person.valid? end def test_validates_numericality_of_less_than_odd_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom' @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :message => 'custom'}) @person.valid? end diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index e41635134c..0b0f5682aa 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -3,7 +3,7 @@ module ActiveRecord class AssociatedValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return if (value.is_a?(Array) ? value : [value]).collect{ |r| r.nil? || r.valid? }.all? - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) + record.errors.add(attribute, :invalid, options.merge(:value => value)) end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 6283bdd0d6..f2561075e8 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -32,7 +32,7 @@ module ActiveRecord end if relation.exists? - record.errors.add(attribute, :taken, :default => options[:message], :value => value) + record.errors.add(attribute, :taken, options.merge(:value => value)) end end diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb index 8ee2a5868c..454e42ed37 100644 --- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb @@ -9,22 +9,22 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase I18n.backend = I18n::Backend::Simple.new end - # validates_associated: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + # validates_associated: generate_message(attr_name, :invalid, :message => custom_message, :value => value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :default => nil, :value => 'title') + assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :value => 'title') end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') end - # validates_uniqueness_of: generate_message(attr_name, :taken, :default => configuration[:message]) + # validates_uniqueness_of: generate_message(attr_name, :taken, :message => custom_message) def test_generate_message_taken_with_default_message - assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :default => nil, :value => 'title') + assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :value => 'title') end def test_generate_message_taken_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :default => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :message => 'custom message %{value}', :value => 'title') end # ActiveRecord#RecordInvalid exception diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 38fa2b821d..79f32e48ae 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -36,14 +36,14 @@ class I18nValidationTest < ActiveRecord::TestCase def test_validates_uniqueness_of_generates_message Topic.validates_uniqueness_of :title @topic.title = unique_topic.title - @topic.errors.expects(:generate_message).with(:title, :taken, {:default => nil, :value => 'unique!'}) + @topic.errors.expects(:generate_message).with(:title, :taken, {:value => 'unique!'}) @topic.valid? end def test_validates_uniqueness_of_generates_message_with_custom_default_message Topic.validates_uniqueness_of :title, :message => 'custom' @topic.title = unique_topic.title - @topic.errors.expects(:generate_message).with(:title, :taken, {:default => 'custom', :value => 'unique!'}) + @topic.errors.expects(:generate_message).with(:title, :taken, {:message => 'custom', :value => 'unique!'}) @topic.valid? end @@ -51,13 +51,13 @@ class I18nValidationTest < ActiveRecord::TestCase def test_validates_associated_generates_message Topic.validates_associated :replies - replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies}) replied_topic.valid? end def test_validates_associated_generates_message_with_custom_default_message Topic.validates_associated :replies - replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies}) replied_topic.valid? end -- cgit v1.2.3 From da90fe94662b338a2430e99ff0d3298059a28a51 Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Sat, 15 May 2010 20:07:13 +0200 Subject: make sure `as` is set before trying to build an #{as}_counter. [#2804 state:resolved] Signed-off-by: Jeremy Kemper --- actionpack/lib/action_view/render/partials.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 6160a95e20..5d266c46bf 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -248,7 +248,7 @@ module ActionView @collection.each do |object| locals[counter_name] += 1 - locals["#{as.to_s}_counter".to_sym] = locals[counter_name] + locals["#{as.to_s}_counter".to_sym] = locals[counter_name] if as locals[as] = object segments << template.render(@view, locals) -- cgit v1.2.3 From c5537c1158c91e3244d24751b1e86290b136dc09 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 15 May 2010 11:25:56 -0700 Subject: Ruby 1.9: fix invalid rack response in test --- actionpack/test/dispatch/request/xml_params_parsing_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index f2ce2c5b93..d44c642420 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -21,7 +21,7 @@ class XmlParamsParsingTest < ActionController::IntegrationTest def call(env) bar = env['action_dispatch.request.request_parameters']['foo'] result = "#{bar}" - [200, {"Content-Type" => "application/xml", "Content-Length" => result.length.to_s}, result] + [200, {"Content-Type" => "application/xml", "Content-Length" => result.length.to_s}, [result]] end end req = Rack::MockRequest.new(ActionDispatch::ParamsParser.new(Linted.new)) -- cgit v1.2.3 From f055bc05d515b80c89b99b775546b954f270bc5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 May 2010 21:55:03 +0200 Subject: Optimize the code added in fa99de0bd054576336c9 --- actionpack/lib/action_view/render/partials.rb | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 5d266c46bf..85f67d4f14 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -241,16 +241,21 @@ module ActionView end def collection_with_template(template = @template) - segments, locals, as, template = [], @locals, @options[:as] || @template.variable_name, @template + segments, locals, template = [], @locals, @template - counter_name = template.counter_name - locals[counter_name] = -1 + if @options[:as] + as = @options[:as] + counter = "#{as}_counter".to_sym + else + as = template.variable_name + counter = template.counter_name + end + + locals[counter] = -1 @collection.each do |object| - locals[counter_name] += 1 - locals["#{as.to_s}_counter".to_sym] = locals[counter_name] if as + locals[counter] += 1 locals[as] = object - segments << template.render(@view, locals) end @@ -258,13 +263,18 @@ module ActionView end def collection_without_template(collection_paths = @collection_paths) - segments, locals, as = [], @locals, @options[:as] - index, template = -1, nil + segments, locals = [], @locals + index, template = -1, nil + + if @options[:as] + as = @options[:as] + counter = "#{as}_counter" + end @collection.each_with_index do |object, i| template = find_template(collection_paths[i]) - locals[template.counter_name] = (index += 1) locals[as || template.variable_name] = object + locals[counter || template.counter_name] = (index += 1) segments << template.render(@view, locals) end -- cgit v1.2.3 From d6cbb27e7b260c970bf7d07dc0b0591ed82cee2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 May 2010 21:55:16 +0200 Subject: Revert "Make ActiveModel::Errors#add_on_blank and #add_on_empty accept an options hash and make various Validators pass their (filtered) options." Having a huge array to whitelist options is not the proper way to handle this case. This means that the ActiveModel::Errors object should know about the options given in *all* validators and break the extensibility added by the validators itself. If the intent is to whitelist options before sending them to I18n, each validator should clean its respective options instead of throwing the responsibility to the Errors object. This reverts commit bc1c8d58ec45593acba614d1d0fecb49adef08ff. --- activemodel/lib/active_model/errors.rb | 54 ++++---------- .../lib/active_model/validations/acceptance.rb | 2 +- .../lib/active_model/validations/confirmation.rb | 2 +- .../lib/active_model/validations/exclusion.rb | 2 +- activemodel/lib/active_model/validations/format.rb | 4 +- .../lib/active_model/validations/inclusion.rb | 2 +- activemodel/lib/active_model/validations/length.rb | 4 +- .../lib/active_model/validations/numericality.rb | 8 +-- .../lib/active_model/validations/presence.rb | 2 +- .../i18n_generate_message_validation_test.rb | 82 +++++++++++----------- .../test/cases/validations/i18n_validation_test.rb | 64 ++++++++--------- .../lib/active_record/validations/associated.rb | 2 +- .../lib/active_record/validations/uniqueness.rb | 2 +- .../i18n_generate_message_validation_test.rb | 12 ++-- .../test/cases/validations/i18n_validation_test.rb | 8 +-- 15 files changed, 111 insertions(+), 139 deletions(-) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index b18b62f926..14afc5265f 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -179,45 +179,25 @@ module ActiveModel # If +message+ is a Proc, it will be called, allowing for things like Time.now to be used within an error def add(attribute, message = nil, options = {}) message ||= :invalid - - reserved = [:minimum, :maximum, :is, :within , :in, :allow_nil, :allow_blank, :case_sensitive, - :too_long, :too_short, :wrong_length, :on, :if, :unless , :tokenizer, :invalid, - :only_integer, :odd, :even, :less_than, :with, :accept] - - message = generate_message(attribute, message, options.except(*reserved)) if message.is_a?(Symbol) - + message = generate_message(attribute, message, options) if message.is_a?(Symbol) message = message.call if message.is_a?(Proc) self[attribute] << message end # Will add an error message to each of the attributes in +attributes+ that is empty. - def add_on_empty(attributes, options = {}) - if options && !options.is_a?(Hash) - options = { :message => options } - ActiveSupport::Deprecation.warn \ - "ActiveModel::Errors#add_on_empty(attributes, custom_message) has been deprecated.\n" + - "Instead of passing a custom_message pass an options Hash { :message => custom_message }." - end - + def add_on_empty(attributes, custom_message = nil) [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) is_empty = value.respond_to?(:empty?) ? value.empty? : false - add(attribute, :empty, options) if value.nil? || is_empty + add(attribute, :empty, :default => custom_message) unless !value.nil? && !is_empty end end # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). - def add_on_blank(attributes, options = {}) - if options && !options.is_a?(Hash) - options = { :message => options } - ActiveSupport::Deprecation.warn \ - "ActiveModel::Errors#add_on_blank(attributes, custom_message) has been deprecated.\n" + - "Instead of passing a custom_message pass an options Hash { :message => custom_message }." - end - + def add_on_blank(attributes, custom_message = nil) [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) - add(attribute, :blank, options) if value.blank? + add(attribute, :blank, :default => custom_message) if value.blank? end end @@ -274,26 +254,18 @@ module ActiveModel #
  • errors.attributes.title.blank
  • #
  • errors.messages.blank
  • # - - def generate_message(attribute, type = :invalid, options = {}) - type = options.delete(:message) if options[:message].is_a?(Symbol) - - if options[:default] - ActiveSupport::Deprecation.warn \ - "ActiveModel::Errors#generate_message(attributes, custom_message) has been deprecated.\n" + - "Use ActiveModel::Errors#generate_message(attributes, :message => 'your message') instead." - options[:message] = options.delete(:default) - end + def generate_message(attribute, message = :invalid, options = {}) + message, options[:default] = options[:default], message if options[:default].is_a?(Symbol) defaults = @base.class.lookup_ancestors.map do |klass| - [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{type}", - :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{type}" ] + [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{message}", + :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{message}" ] end - defaults << options.delete(:message) - defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" - defaults << :"errors.attributes.#{attribute}.#{type}" - defaults << :"errors.messages.#{type}" + defaults << options.delete(:default) + defaults << :"#{@base.class.i18n_scope}.errors.messages.#{message}" + defaults << :"errors.attributes.#{attribute}.#{message}" + defaults << :"errors.messages.#{message}" defaults.compact! defaults.flatten! diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index ced083b312..26b12b504b 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -7,7 +7,7 @@ module ActiveModel def validate_each(record, attribute, value) unless value == options[:accept] - record.errors.add(attribute, :accepted, options) + record.errors.add(attribute, :accepted, :default => options[:message]) end end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 66bce0d2de..51445343f2 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -4,7 +4,7 @@ module ActiveModel def validate_each(record, attribute, value) confirmed = record.send(:"#{attribute}_confirmation") return if confirmed.nil? || value == confirmed - record.errors.add(attribute, :confirmation, options) + record.errors.add(attribute, :confirmation, :default => options[:message]) end def setup(klass) diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index da4c84fbd6..2ee78f5dd2 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return unless options[:in].include?(value) - record.errors.add(attribute, :exclusion, options.merge(:value => value)) + record.errors.add(attribute, :exclusion, :default => options[:message], :value => value) end end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 2667baa5a0..c34c860d4d 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -3,9 +3,9 @@ module ActiveModel class FormatValidator < EachValidator def validate_each(record, attribute, value) if options[:with] && value.to_s !~ options[:with] - record.errors.add(attribute, :invalid, options.merge(:value => value)) + record.errors.add(attribute, :invalid, :default => options[:message], :value => value) elsif options[:without] && value.to_s =~ options[:without] - record.errors.add(attribute, :invalid, options.merge(:value => value)) + record.errors.add(attribute, :invalid, :default => options[:message], :value => value) end end diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 0ddf191b4f..446646d247 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return if options[:in].include?(value) - record.errors.add(attribute, :inclusion, options.merge(:value => value)) + record.errors.add(attribute, :inclusion, :default => options[:message], :value => value) end end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 9b671f58de..d7218f4f52 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -37,7 +37,7 @@ module ActiveModel CHECKS.each do |key, validity_check| next unless check_value = options[key] - options[:message] ||= options[MESSAGES[key]] if options[MESSAGES[key]] + custom_message = options[:message] || options[MESSAGES[key]] valid_value = if key == :maximum value.nil? || value.size.send(validity_check, check_value) @@ -46,7 +46,7 @@ module ActiveModel end next if valid_value - record.errors.add(attribute, MESSAGES[key], options.merge(:count => check_value)) + record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) end end end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index d407258442..716010e88b 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -26,13 +26,13 @@ module ActiveModel return if options[:allow_nil] && raw_value.nil? unless value = parse_raw_value_as_a_number(raw_value) - record.errors.add(attr_name, :not_a_number, options.merge(:value => raw_value)) + record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message]) return end if options[:only_integer] unless value = parse_raw_value_as_an_integer(raw_value) - record.errors.add(attr_name, :not_an_integer, options.merge(:value => raw_value)) + record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message]) return end end @@ -41,14 +41,14 @@ module ActiveModel case option when :odd, :even unless value.to_i.send(CHECKS[option]) - record.errors.add(attr_name, option, options.merge(:value => value)) + record.errors.add(attr_name, option, :value => value, :default => options[:message]) end else option_value = option_value.call(record) if option_value.is_a?(Proc) option_value = record.send(option_value) if option_value.is_a?(Symbol) unless value.send(CHECKS[option], option_value) - record.errors.add(attr_name, option, options.merge(:value => value, :count => option_value)) + record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value) end end end diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index 2826a10ffe..b319f4834b 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -4,7 +4,7 @@ module ActiveModel module Validations class PresenceValidator < EachValidator def validate(record) - record.errors.add_on_blank(attributes, options) + record.errors.add_on_blank(attributes, options[:message]) end end diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index 0679e67f84..58a8d179ad 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -8,131 +8,131 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase @person = Person.new end - # validates_inclusion_of: generate_message(attr_name, :inclusion, :message => custom_message, :value => value) + # validates_inclusion_of: generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) def test_generate_message_inclusion_with_default_message - assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, :value => 'title') + assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, :default => nil, :value => 'title') end def test_generate_message_inclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :default => 'custom message %{value}', :value => 'title') end - # validates_exclusion_of: generate_message(attr_name, :exclusion, :message => custom_message, :value => value) + # validates_exclusion_of: generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) def test_generate_message_exclusion_with_default_message - assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, :value => 'title') + assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, :default => nil, :value => 'title') end def test_generate_message_exclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :default => 'custom message %{value}', :value => 'title') end - # validates_format_of: generate_message(attr_name, :invalid, :message => custom_message, :value => value) + # validates_format_of: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, :value => 'title') + assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, :default => nil, :value => 'title') end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title') end - # validates_confirmation_of: generate_message(attr_name, :confirmation, :message => custom_message) + # validates_confirmation_of: generate_message(attr_name, :confirmation, :default => configuration[:message]) def test_generate_message_confirmation_with_default_message - assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation) + assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation, :default => nil) end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :default => 'custom message') end - # validates_acceptance_of: generate_message(attr_name, :accepted, :message => custom_message) + # validates_acceptance_of: generate_message(attr_name, :accepted, :default => configuration[:message]) def test_generate_message_accepted_with_default_message - assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted) + assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted, :default => nil) end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :default => 'custom message') end - # add_on_empty: generate_message(attr, :empty, :message => custom_message) + # add_on_empty: generate_message(attr, :empty, :default => custom_message) def test_generate_message_empty_with_default_message - assert_equal "can't be empty", @person.errors.generate_message(:title, :empty) + assert_equal "can't be empty", @person.errors.generate_message(:title, :empty, :default => nil) end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :default => 'custom message') end - # add_on_blank: generate_message(attr, :blank, :message => custom_message) + # add_on_blank: generate_message(attr, :blank, :default => custom_message) def test_generate_message_blank_with_default_message - assert_equal "can't be blank", @person.errors.generate_message(:title, :blank) + assert_equal "can't be blank", @person.errors.generate_message(:title, :blank, :default => nil) end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :default => 'custom message') end - # validates_length_of: generate_message(attr, :too_long, :message => custom_message, :count => option_value.end) + # validates_length_of: generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) def test_generate_message_too_long_with_default_message - assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :count => 10) + assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :default => nil, :count => 10) end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :default => 'custom message %{count}', :count => 10) end - # validates_length_of: generate_message(attr, :too_short, :default => custom_message, :count => option_value.begin) + # validates_length_of: generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin) def test_generate_message_too_short_with_default_message - assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :count => 10) + assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :default => nil, :count => 10) end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :default => 'custom message %{count}', :count => 10) end - # validates_length_of: generate_message(attr, :wrong_length, :message => custom_message, :count => option_value) + # validates_length_of: generate_message(attr, key, :default => custom_message, :count => option_value) def test_generate_message_wrong_length_with_default_message - assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :count => 10) + assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :default => nil, :count => 10) end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :default => 'custom message %{count}', :count => 10) end - # validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :message => custom_message) + # validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) def test_generate_message_not_a_number_with_default_message - assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, :value => 'title') + assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, :default => nil, :value => 'title') end def test_generate_message_not_a_number_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :default => 'custom message %{value}', :value => 'title') end - # validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => custom_message) + # validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => configuration[:message]) def test_generate_message_greater_than_with_default_message - assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, :value => 'title', :count => 10) + assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, :default => nil, :value => 'title', :count => 10) end def test_generate_message_greater_than_or_equal_to_with_default_message - assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, :value => 'title', :count => 10) + assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, :default => nil, :value => 'title', :count => 10) end def test_generate_message_equal_to_with_default_message - assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, :value => 'title', :count => 10) + assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, :default => nil, :value => 'title', :count => 10) end def test_generate_message_less_than_with_default_message - assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, :value => 'title', :count => 10) + assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, :default => nil, :value => 'title', :count => 10) end def test_generate_message_less_than_or_equal_to_with_default_message - assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, :value => 'title', :count => 10) + assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, :default => nil, :value => 'title', :count => 10) end def test_generate_message_odd_with_default_message - assert_equal "must be odd", @person.errors.generate_message(:title, :odd, :value => 'title', :count => 10) + assert_equal "must be odd", @person.errors.generate_message(:title, :odd, :default => nil, :value => 'title', :count => 10) end def test_generate_message_even_with_default_message - assert_equal "must be even", @person.errors.generate_message(:title, :even, :value => 'title', :count => 10) + assert_equal "must be even", @person.errors.generate_message(:title, :even, :default => nil, :value => 'title', :count => 10) end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index eff2b78e74..547d80f46e 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -22,23 +22,23 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_add_on_empty_generates_message - @person.errors.expects(:generate_message).with(:title, :empty, {}) + @person.errors.expects(:generate_message).with(:title, :empty, {:default => nil}) @person.errors.add_on_empty :title end def test_errors_add_on_empty_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :empty, {:message => 'custom'}) - @person.errors.add_on_empty :title, :message => 'custom' + @person.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'}) + @person.errors.add_on_empty :title, 'custom' end def test_errors_add_on_blank_generates_message - @person.errors.expects(:generate_message).with(:title, :blank, {}) + @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) @person.errors.add_on_blank :title end def test_errors_add_on_blank_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'}) - @person.errors.add_on_blank :title, :message => 'custom' + @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) + @person.errors.add_on_blank :title, 'custom' end def test_full_message_encoding @@ -66,14 +66,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_confirmation_of_generates_message Person.validates_confirmation_of :title @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {}) + @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil}) @person.valid? end def test_validates_confirmation_of_generates_message_with_custom_default_message Person.validates_confirmation_of :title, :message => 'custom' @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {:message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'}) @person.valid? end @@ -81,13 +81,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_acceptance_of_generates_message Person.validates_acceptance_of :title, :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {}) + @person.errors.expects(:generate_message).with(:title, :accepted, {:default => nil}) @person.valid? end def test_validates_acceptance_of_generates_message_with_custom_default_message Person.validates_acceptance_of :title, :message => 'custom', :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {:message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'}) @person.valid? end @@ -95,13 +95,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_presence_of_generates_message Person.validates_presence_of :title - @person.errors.expects(:generate_message).with(:title, :blank, {}) + @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) @person.valid? end def test_validates_presence_of_generates_message_with_custom_default_message Person.validates_presence_of :title, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) @person.valid? end @@ -109,27 +109,27 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_length_of_within_generates_message_with_title_too_short Person.validates_length_of :title, :within => 3..5 - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3}) + @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message Person.validates_length_of :title, :within => 3..5, :too_short => 'custom' - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_long Person.validates_length_of :title, :within => 3..5 @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5}) + @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) @person.valid? end def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message Person.validates_length_of :title, :within => 3..5, :too_long => 'custom' @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) @person.valid? end @@ -137,13 +137,13 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_length_of_is_generates_message Person.validates_length_of :title, :is => 5 - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5}) + @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil}) @person.valid? end def test_validates_length_of_is_generates_message_with_custom_default_message Person.validates_length_of :title, :is => 5, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'}) @person.valid? end @@ -152,14 +152,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_format_of_generates_message Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x'}) + @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil}) @person.valid? end def test_validates_format_of_generates_message_with_custom_default_message Person.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom' @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'}) @person.valid? end @@ -168,14 +168,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_inclusion_of_generates_message Person.validates_inclusion_of :title, :in => %w(a b c) @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z'}) + @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil}) @person.valid? end def test_validates_inclusion_of_generates_message_with_custom_default_message Person.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom' @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'}) @person.valid? end @@ -184,14 +184,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_exclusion_of_generates_message Person.validates_exclusion_of :title, :in => %w(a b c) @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a'}) + @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil}) @person.valid? end def test_validates_exclusion_of_generates_message_with_custom_default_message Person.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom' @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'}) @person.valid? end @@ -200,14 +200,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_generates_message Person.validates_numericality_of :title @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a'}) + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil}) @person.valid? end def test_validates_numericality_of_generates_message_with_custom_default_message Person.validates_numericality_of :title, :message => 'custom' @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) @person.valid? end @@ -216,14 +216,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_only_integer_generates_message Person.validates_numericality_of :title, :only_integer => true @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0'}) + @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil}) @person.valid? end def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :message => 'custom' @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'}) @person.valid? end @@ -232,14 +232,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_odd_generates_message Person.validates_numericality_of :title, :only_integer => true, :odd => true @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0}) + @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil}) @person.valid? end def test_validates_numericality_of_odd_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom' @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'}) @person.valid? end @@ -248,14 +248,14 @@ class I18nValidationTest < ActiveModel::TestCase def test_validates_numericality_of_less_than_generates_message Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0}) + @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil}) @person.valid? end def test_validates_numericality_of_less_than_odd_generates_message_with_custom_default_message Person.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom' @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :message => 'custom'}) + @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'}) @person.valid? end diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index 0b0f5682aa..e41635134c 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -3,7 +3,7 @@ module ActiveRecord class AssociatedValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return if (value.is_a?(Array) ? value : [value]).collect{ |r| r.nil? || r.valid? }.all? - record.errors.add(attribute, :invalid, options.merge(:value => value)) + record.errors.add(attribute, :invalid, :default => options[:message], :value => value) end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index f2561075e8..6283bdd0d6 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -32,7 +32,7 @@ module ActiveRecord end if relation.exists? - record.errors.add(attribute, :taken, options.merge(:value => value)) + record.errors.add(attribute, :taken, :default => options[:message], :value => value) end end diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb index 454e42ed37..8ee2a5868c 100644 --- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb @@ -9,22 +9,22 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase I18n.backend = I18n::Backend::Simple.new end - # validates_associated: generate_message(attr_name, :invalid, :message => custom_message, :value => value) + # validates_associated: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :value => 'title') + assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :default => nil, :value => 'title') end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title') end - # validates_uniqueness_of: generate_message(attr_name, :taken, :message => custom_message) + # validates_uniqueness_of: generate_message(attr_name, :taken, :default => configuration[:message]) def test_generate_message_taken_with_default_message - assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :value => 'title') + assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :default => nil, :value => 'title') end def test_generate_message_taken_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :default => 'custom message %{value}', :value => 'title') end # ActiveRecord#RecordInvalid exception diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 79f32e48ae..38fa2b821d 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -36,14 +36,14 @@ class I18nValidationTest < ActiveRecord::TestCase def test_validates_uniqueness_of_generates_message Topic.validates_uniqueness_of :title @topic.title = unique_topic.title - @topic.errors.expects(:generate_message).with(:title, :taken, {:value => 'unique!'}) + @topic.errors.expects(:generate_message).with(:title, :taken, {:default => nil, :value => 'unique!'}) @topic.valid? end def test_validates_uniqueness_of_generates_message_with_custom_default_message Topic.validates_uniqueness_of :title, :message => 'custom' @topic.title = unique_topic.title - @topic.errors.expects(:generate_message).with(:title, :taken, {:message => 'custom', :value => 'unique!'}) + @topic.errors.expects(:generate_message).with(:title, :taken, {:default => 'custom', :value => 'unique!'}) @topic.valid? end @@ -51,13 +51,13 @@ class I18nValidationTest < ActiveRecord::TestCase def test_validates_associated_generates_message Topic.validates_associated :replies - replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies}) + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) replied_topic.valid? end def test_validates_associated_generates_message_with_custom_default_message Topic.validates_associated :replies - replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies}) + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) replied_topic.valid? end -- cgit v1.2.3 From 6617d0189377a2f820c8f948589bb2d4a91155af Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Sat, 15 May 2010 16:22:35 -0400 Subject: Sending :id => nil to form helpers now properly omits the "id" html element [#4559 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/form_helper.rb | 16 +++- actionpack/test/template/form_helper_test.rb | 107 ++++++++++++++++++++++ 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 932e9e2f95..414a5d4cd9 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -859,7 +859,13 @@ module ActionView options = options.stringify_keys tag_value = options.delete("value") name_and_id = options.dup - name_and_id["id"] = name_and_id["for"] + + if name_and_id["for"] + name_and_id["id"] = name_and_id["for"] + else + name_and_id.delete("id") + end + add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") options["for"] ||= name_and_id["id"] @@ -1027,7 +1033,7 @@ module ActionView pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase specified_id = options["id"] add_default_name_and_id(options) - options["id"] += "_#{pretty_tag_value}" unless specified_id + options["id"] += "_#{pretty_tag_value}" if specified_id.blank? && options["id"].present? else add_default_name_and_id(options) end @@ -1036,14 +1042,14 @@ module ActionView def add_default_name_and_id(options) if options.has_key?("index") options["name"] ||= tag_name_with_index(options["index"]) - options["id"] ||= tag_id_with_index(options["index"]) + options["id"] = options.fetch("id", tag_id_with_index(options["index"])) options.delete("index") elsif defined?(@auto_index) options["name"] ||= tag_name_with_index(@auto_index) - options["id"] ||= tag_id_with_index(@auto_index) + options["id"] = options.fetch("id", tag_id_with_index(@auto_index)) else options["name"] ||= tag_name + (options.has_key?('multiple') ? '[]' : '') - options["id"] ||= tag_id + options["id"] = options.fetch("id", tag_id) end end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index da2adc9869..3893d152a2 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -423,6 +423,90 @@ class FormHelperTest < ActionView::TestCase check_box("post", "secret", :id => "i mean it") end + def test_nil_id + assert_dom_equal( + '', text_field("post", "title", "id" => nil) + ) + assert_dom_equal( + '', + text_area("post", "body", "id" => nil) + ) + assert_dom_equal( + '', + check_box("post", "secret", "id" => nil) + ) + assert_dom_equal( + '', + radio_button("post", "secret", "0", "id" => nil) + ) + assert_dom_equal( + '', + select("post", "secret", [], {}, "id" => nil) + ) + assert_dom_equal text_field("post", "title", "id" => nil), + text_field("post", "title", :id => nil) + assert_dom_equal text_area("post", "body", "id" => nil), + text_area("post", "body", :id => nil) + assert_dom_equal check_box("post", "secret", "id" => nil), + check_box("post", "secret", :id => nil) + assert_dom_equal radio_button("post", "secret", "id" => nil), + radio_button("post", "secret", :id => nil) + end + + def test_index + assert_dom_equal( + '', + text_field("post", "title", "index" => 5) + ) + assert_dom_equal( + '', + text_area("post", "body", "index" => 5) + ) + assert_dom_equal( + '', + check_box("post", "secret", "index" => 5) + ) + assert_dom_equal( + text_field("post", "title", "index" => 5), + text_field("post", "title", "index" => 5) + ) + assert_dom_equal( + text_area("post", "body", "index" => 5), + text_area("post", "body", "index" => 5) + ) + assert_dom_equal( + check_box("post", "secret", "index" => 5), + check_box("post", "secret", "index" => 5) + ) + end + + def test_index_with_nil_id + assert_dom_equal( + '', + text_field("post", "title", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + '', + text_area("post", "body", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + '', + check_box("post", "secret", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + text_field("post", "title", "index" => 5, 'id' => nil), + text_field("post", "title", :index => 5, :id => nil) + ) + assert_dom_equal( + text_area("post", "body", "index" => 5, 'id' => nil), + text_area("post", "body", :index => 5, :id => nil) + ) + assert_dom_equal( + check_box("post", "secret", "index" => 5, 'id' => nil), + check_box("post", "secret", :index => 5, :id => nil) + ) + end + def test_auto_index pid = @post.id assert_dom_equal( @@ -449,6 +533,29 @@ class FormHelperTest < ActionView::TestCase ) end + def test_auto_index_with_nil_id + pid = @post.id + assert_dom_equal( + "", + text_field("post[]","title", :id => nil) + ) + assert_dom_equal( + "", + text_area("post[]", "body", :id => nil) + ) + assert_dom_equal( + "", + check_box("post[]", "secret", :id => nil) + ) + assert_dom_equal( +"", + radio_button("post[]", "title", "Hello World", :id => nil) + ) + assert_dom_equal("", + radio_button("post[]", "title", "Goodbye World", :id => nil) + ) + end + def test_form_for assert_deprecated do form_for(:post, @post, :html => { :id => 'create-post' }) do |f| -- cgit v1.2.3 From 351816fab6dbe564b7bddbd877648edb06a2bfb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 May 2010 23:48:56 +0200 Subject: Ensure that eager_load actually takes place just after the middleware stack is built by using another pattern. Also create a engine_blank_point initializer to ensure any :before or :after hooks defined inside engines won't move the configuration initializers to other places. --- railties/lib/rails/application/finisher.rb | 10 ++++++++-- railties/lib/rails/engine.rb | 25 ++++++++++++------------- railties/lib/rails/railtie.rb | 3 +++ railties/test/railties/engine_test.rb | 26 ++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 03bc270c81..9d04f1ce38 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -35,8 +35,14 @@ module Rails app end - initializer :finisher_hook do |app| - ActiveSupport.run_load_hooks(:after_initialize, app) + initializer :eager_load! do + if config.cache_classes && !$rails_rake_task + railties.all(&:eager_load!) + end + end + + initializer :finisher_hook do + ActiveSupport.run_load_hooks(:after_initialize, self) end # Disable dependency loading during request cycle diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 652bd40ee4..b44755820c 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -132,6 +132,15 @@ module Rails config.paths.lib.tasks.to_a.sort.each { |ext| load(ext) } end + def eager_load! + config.eager_load_paths.each do |load_path| + matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/ + Dir.glob("#{load_path}/**/*.rb").sort.each do |file| + require_dependency file.sub(matcher, '\1') + end + end + end + # Add configured load paths to ruby load paths and remove duplicates. initializer :set_load_path, :before => :bootstrap_hook do config.load_paths.reverse_each do |path| @@ -203,19 +212,9 @@ module Rails end end - # This needs to be an initializer, since it needs to run once - # per engine and get the engine as a block parameter - initializer :load_app_classes, :before => :finisher_hook do |app| - next if $rails_rake_task - - if app.config.cache_classes - config.eager_load_paths.each do |load_path| - matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/ - Dir.glob("#{load_path}/**/*.rb").sort.each do |file| - require_dependency file.sub(matcher, '\1') - end - end - end + initializer :engines_blank_point do + # We need this initializer so all extra initializers added in engines are + # consistently executed after all the initializers above across all engines. end protected diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index b6b57bc5b5..1dba6e1538 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -197,6 +197,9 @@ module Rails end end + def eager_load! + end + def rake_tasks self.class.rake_tasks end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 40ac11fa03..b3f65fd00d 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -28,5 +28,31 @@ module RailtiesTest boot_rails assert !Rails::Engine.respond_to?(:config) end + + test "initializers are executed after application configuration initializers" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + initializer "dummy_initializer" do + end + end + end + RUBY + + boot_rails + + initializers = Rails.application.initializers + index = initializers.index { |i| i.name == "dummy_initializer" } + selection = initializers[(index-3)..(index)].map(&:name).map(&:to_s) + + assert_equal %w( + load_config_initializers + load_config_initializers + engines_blank_point + dummy_initializer + ), selection + + assert index < initializers.index { |i| i.name == :build_middleware_stack } + end end end -- cgit v1.2.3 From 3afdfc35e8aec7e6379e093dd1278cb3de54f21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 16 May 2010 00:34:54 +0200 Subject: Expose remaining hooks to minimize the need for a Railtie based on feedback from plugin developers. --- railties/lib/rails/application.rb | 1 - railties/lib/rails/application/finisher.rb | 1 + railties/lib/rails/railtie/configuration.rb | 12 +++ .../test/application/initializers/hooks_test.rb | 86 ++++++++++++++++++++++ .../application/initializers/initializers_test.rb | 68 ----------------- 5 files changed, 99 insertions(+), 69 deletions(-) create mode 100644 railties/test/application/initializers/hooks_test.rb delete mode 100644 railties/test/application/initializers/initializers_test.rb diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 9e18dccf69..a3b3a56bc8 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -69,7 +69,6 @@ module Rails raise "You cannot have more than one Rails::Application" if Rails.application super Rails.application = base.instance - ActiveSupport.run_load_hooks(:before_configuration, base.instance) end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 9d04f1ce38..fbab4d5515 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -37,6 +37,7 @@ module Rails initializer :eager_load! do if config.cache_classes && !$rails_rake_task + ActiveSupport.run_load_hooks(:before_eager_load, self) railties.all(&:eager_load!) end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index f57d82a3d8..c4a315708b 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -68,6 +68,18 @@ module Rails end end + def before_configuration(&block) + ActiveSupport.on_load(:before_configuration, :yield => true, &block) + end + + def before_eager_load(&block) + ActiveSupport.on_load(:before_eager_load, :yield => true, &block) + end + + def before_initialize(&block) + ActiveSupport.on_load(:before_initialize, :yield => true, &block) + end + def after_initialize(&block) ActiveSupport.on_load(:after_initialize, :yield => true, &block) end diff --git a/railties/test/application/initializers/hooks_test.rb b/railties/test/application/initializers/hooks_test.rb new file mode 100644 index 0000000000..1316bf6ee2 --- /dev/null +++ b/railties/test/application/initializers/hooks_test.rb @@ -0,0 +1,86 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class InitializersTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + test "load initializers" do + app_file "config/initializers/foo.rb", "$foo = true" + require "#{app_path}/config/environment" + assert $foo + end + + test "hooks block works correctly without cache classes (before_eager_load is not called)" do + add_to_config <<-RUBY + $initialization_callbacks = [] + config.root = "#{app_path}" + config.cache_classes = false + config.before_configuration { $initialization_callbacks << 1 } + config.before_initialize { $initialization_callbacks << 2 } + config.before_eager_load { Boom } + config.after_initialize { $initialization_callbacks << 3 } + RUBY + + require "#{app_path}/config/environment" + assert_equal [1,2,3], $initialization_callbacks + end + + test "hooks block works correctly with cache classes" do + add_to_config <<-RUBY + $initialization_callbacks = [] + config.root = "#{app_path}" + config.cache_classes = true + config.before_configuration { $initialization_callbacks << 1 } + config.before_initialize { $initialization_callbacks << 2 } + config.before_eager_load { $initialization_callbacks << 3 } + config.after_initialize { $initialization_callbacks << 4 } + RUBY + + require "#{app_path}/config/environment" + assert_equal [1,2,3,4], $initialization_callbacks + end + + test "after_initialize runs after frameworks have been initialized" do + $activerecord_configurations = nil + add_to_config <<-RUBY + config.after_initialize { $activerecord_configurations = ActiveRecord::Base.configurations } + RUBY + + require "#{app_path}/config/environment" + assert $activerecord_configurations + assert $activerecord_configurations['development'] + end + + test "after_initialize happens after to_prepare in development" do + $order = [] + add_to_config <<-RUBY + config.cache_classes = false + config.after_initialize { $order << :after_initialize } + config.to_prepare { $order << :to_prepare } + RUBY + + require "#{app_path}/config/environment" + assert [:to_prepare, :after_initialize], $order + end + + test "after_initialize happens after to_prepare in production" do + $order = [] + add_to_config <<-RUBY + config.cache_classes = true + config.after_initialize { $order << :after_initialize } + config.to_prepare { $order << :to_prepare } + RUBY + + require "#{app_path}/config/application" + Rails.env.replace "production" + require "#{app_path}/config/environment" + assert [:to_prepare, :after_initialize], $order + end + end +end diff --git a/railties/test/application/initializers/initializers_test.rb b/railties/test/application/initializers/initializers_test.rb deleted file mode 100644 index eca42dada6..0000000000 --- a/railties/test/application/initializers/initializers_test.rb +++ /dev/null @@ -1,68 +0,0 @@ -require "isolation/abstract_unit" - -module ApplicationTests - class InitializersTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - FileUtils.rm_rf "#{app_path}/config/environments" - end - - test "load initializers" do - app_file "config/initializers/foo.rb", "$foo = true" - require "#{app_path}/config/environment" - assert $foo - end - - test "after_initialize block works correctly" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.after_initialize { $test_after_initialize_block1 = "success" } - config.after_initialize { $test_after_initialize_block2 = "congratulations" } - RUBY - require "#{app_path}/config/environment" - - assert_equal "success", $test_after_initialize_block1 - assert_equal "congratulations", $test_after_initialize_block2 - end - - test "after_initialize runs after frameworks have been initialized" do - $activerecord_configurations = nil - add_to_config <<-RUBY - config.after_initialize { $activerecord_configurations = ActiveRecord::Base.configurations } - RUBY - - require "#{app_path}/config/environment" - assert $activerecord_configurations - assert $activerecord_configurations['development'] - end - - test "after_initialize happens after to_prepare in development" do - $order = [] - add_to_config <<-RUBY - config.cache_classes = false - config.after_initialize { $order << :after_initialize } - config.to_prepare { $order << :to_prepare } - RUBY - - require "#{app_path}/config/environment" - assert [:to_prepare, :after_initialize], $order - end - - test "after_initialize happens after to_prepare in production" do - $order = [] - add_to_config <<-RUBY - config.cache_classes = true - config.after_initialize { $order << :after_initialize } - config.to_prepare { $order << :to_prepare } - RUBY - - require "#{app_path}/config/application" - Rails.env.replace "production" - require "#{app_path}/config/environment" - assert [:to_prepare, :after_initialize], $order - end - end -end -- cgit v1.2.3 From edec1afe25014749f0e2df86d27477b45586a9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elomar=20Fran=C3=A7a?= Date: Sun, 27 Sep 2009 13:42:13 -0300 Subject: Don't carry default value when changing column for a binary type on MySQL [#3234 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/active_record/connection_adapters/mysql_adapter.rb | 6 +++++- activerecord/test/cases/migration_test.rb | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index ec25bbf18e..e12924e63f 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -513,7 +513,7 @@ module ActiveRecord def change_column(table_name, column_name, type, options = {}) #:nodoc: column = column_for(table_name, column_name) - unless options_include_default?(options) + if has_default?(type) && !options_include_default?(options) options[:default] = column.default end @@ -675,6 +675,10 @@ module ActiveRecord end column end + + def has_default?(sql_type) + sql_type =~ :binary || sql_type == :text #mysql forbids defaults on blob and text columns + end end end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index f67344445a..41e27bd281 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -860,6 +860,16 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "Tester", Person.new.first_name end + def test_change_column_type_default_should_change + old_columns = Person.connection.columns(Person.table_name, "#{name} Columns") + assert !old_columns.find { |c| c.name == 'data' } + + assert_nothing_raised do + Person.connection.add_column "people", "data", :string, :default => '' + Person.connection.change_column "people", "data", :binary + end + end + def test_change_column_quotes_column_names Person.connection.create_table :testings do |t| t.column :select, :string -- cgit v1.2.3 From afe57dda26b8ca8484a90801a0fd378dad60e180 Mon Sep 17 00:00:00 2001 From: rohit Date: Sun, 16 May 2010 08:02:44 +0530 Subject: Fixed two failing tests in railties on 1.9.2-head [#4609 state:commited] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/initializers/hooks_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/test/application/initializers/hooks_test.rb b/railties/test/application/initializers/hooks_test.rb index 1316bf6ee2..198abbe861 100644 --- a/railties/test/application/initializers/hooks_test.rb +++ b/railties/test/application/initializers/hooks_test.rb @@ -66,7 +66,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert [:to_prepare, :after_initialize], $order + assert_equal [:to_prepare, :after_initialize], $order end test "after_initialize happens after to_prepare in production" do @@ -80,7 +80,7 @@ module ApplicationTests require "#{app_path}/config/application" Rails.env.replace "production" require "#{app_path}/config/environment" - assert [:to_prepare, :after_initialize], $order + assert_equal [:to_prepare, :after_initialize], $order end end end -- cgit v1.2.3 From 4750e61bfecd210e5c4d96546d638b5cd23bb09e Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Fri, 14 May 2010 22:14:49 +0200 Subject: using :time_select when the attribute type is :time in the scaffold generator. [#2377 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/generated_attribute.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index e962308585..f01934f946 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -9,12 +9,13 @@ module Rails def field_type @field_type ||= case type - when :integer, :float, :decimal then :text_field - when :datetime, :timestamp, :time then :datetime_select - when :date then :date_select - when :string then :text_field - when :text then :text_area - when :boolean then :check_box + when :integer, :float, :decimal then :text_field + when :time then :time_select + when :datetime, :timestamp then :datetime_select + when :date then :date_select + when :string then :text_field + when :text then :text_area + when :boolean then :check_box else :text_field end -- cgit v1.2.3 From 99b38f371a17eb3965f794227279e89fb6c694a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 16 May 2010 12:03:11 +0200 Subject: Move AD::Cascade to the bottom of the middleware stack. --- railties/lib/rails/application/configuration.rb | 4 +-- railties/lib/rails/configuration.rb | 31 +++++++++++++++++++++++ railties/lib/rails/railtie/configuration.rb | 33 +------------------------ 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index cd77f1adaf..9353fbefef 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -150,10 +150,10 @@ module Rails middleware.use('::ActionDispatch::Cookies') middleware.use(lambda { session_store }, lambda { session_options }) middleware.use('::ActionDispatch::Flash', :if => lambda { session_store }) - middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? }) - middleware.use('ActionDispatch::ParamsParser') + middleware.use('::ActionDispatch::ParamsParser') middleware.use('::Rack::MethodOverride') middleware.use('::ActionDispatch::Head') + middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? }) end end end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index bd404f4a14..ee0fca6592 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -5,6 +5,37 @@ require 'rails/rack' module Rails module Configuration + class MiddlewareStackProxy #:nodoc: + def initialize + @operations = [] + end + + def insert_before(*args, &block) + @operations << [:insert_before, args, block] + end + + alias :insert :insert_before + + def insert_after(*args, &block) + @operations << [:insert_after, args, block] + end + + def swap(*args, &block) + @operations << [:swap, args, block] + end + + def use(*args, &block) + @operations << [:use, args, block] + end + + def merge_into(other) + @operations.each do |operation, args, block| + other.send(operation, *args, &block) + end + other + end + end + class Generators #:nodoc: attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index c4a315708b..4e6f94c534 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -3,37 +3,6 @@ require 'rails/configuration' module Rails class Railtie class Configuration - class MiddlewareStackProxy - def initialize - @operations = [] - end - - def insert_before(*args, &block) - @operations << [:insert_before, args, block] - end - - alias insert insert_before - - def insert_after(*args, &block) - @operations << [:insert_after, args, block] - end - - def swap(*args, &block) - @operations << [:swap, args, block] - end - - def use(*args, &block) - @operations << [:use, args, block] - end - - def merge_into(other) - @operations.each do |operation, args, block| - other.send(operation, *args, &block) - end - other - end - end - def initialize @@options ||= {} end @@ -44,7 +13,7 @@ module Rails # application once it is defined and the default_middlewares are # created def app_middleware - @@app_middleware ||= MiddlewareStackProxy.new + @@app_middleware ||= Rails::Configuration::MiddlewareStackProxy.new end # Holds generators configuration: -- cgit v1.2.3 From 5ff6de0982c165bb9038258d867398c73c142084 Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Sun, 16 May 2010 11:20:11 +0200 Subject: Added assert_attribute_type to clean up GeneratedAttributeTest [#2377 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/test_case.rb | 12 +++++++ .../test/generators/generated_attribute_test.rb | 40 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 railties/test/generators/generated_attribute_test.rb diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 6b97c69d8d..24b57aabf9 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -189,6 +189,18 @@ module Rails end alias :assert_method :assert_instance_method + # Asserts the given field name gets translated to an attribute type + # properly. + # + # assert_attribute_type 'date', :date_select + # + def assert_attribute_type(name, attribute_type) + assert_equal( + Rails::Generators::GeneratedAttribute.new('test', name).field_type, + attribute_type + ) + end + # Runs the generator configured for this class. The first argument is an array like # command line arguments: # diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb new file mode 100644 index 0000000000..ccd0c65905 --- /dev/null +++ b/railties/test/generators/generated_attribute_test.rb @@ -0,0 +1,40 @@ +require 'generators/generators_test_helper' +require 'rails/generators/generated_attribute' + +class GeneratedAttributeTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + def test_field_type_returns_text_field + %w(integer float decimal string).each do |name| + assert_attribute_type name, :text_field + end + end + + def test_field_type_returns_datetime_select + %w(datetime timestamp).each do |name| + assert_attribute_type name, :datetime_select + end + end + + def test_field_type_returns_time_select + assert_attribute_type 'time', :time_select + end + + def test_field_type_returns_date_select + assert_attribute_type 'date', :date_select + end + + def test_field_type_returns_text_area + assert_attribute_type 'text', :text_area + end + + def test_field_type_returns_check_box + assert_attribute_type 'boolean', :check_box + end + + def test_field_type_with_unknown_type_returns_text_field + %w(foo bar baz).each do |name| + assert_attribute_type name, :text_field + end + end +end -- cgit v1.2.3 From 1a2d556de7935588e04c541e6c0804b5533db6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 16 May 2010 12:07:44 +0200 Subject: Rename assert_attribute_type to asser_field_type. --- railties/lib/rails/generators/test_case.rb | 6 +++--- railties/test/generators/generated_attribute_test.rb | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 24b57aabf9..952400e049 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -192,11 +192,11 @@ module Rails # Asserts the given field name gets translated to an attribute type # properly. # - # assert_attribute_type 'date', :date_select + # assert_field_type :date, :date_select # - def assert_attribute_type(name, attribute_type) + def assert_field_type(name, attribute_type) assert_equal( - Rails::Generators::GeneratedAttribute.new('test', name).field_type, + Rails::Generators::GeneratedAttribute.new('test', name.to_s).field_type, attribute_type ) end diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb index ccd0c65905..dacb06fb13 100644 --- a/railties/test/generators/generated_attribute_test.rb +++ b/railties/test/generators/generated_attribute_test.rb @@ -6,35 +6,35 @@ class GeneratedAttributeTest < Rails::Generators::TestCase def test_field_type_returns_text_field %w(integer float decimal string).each do |name| - assert_attribute_type name, :text_field + assert_field_type name, :text_field end end def test_field_type_returns_datetime_select %w(datetime timestamp).each do |name| - assert_attribute_type name, :datetime_select + assert_field_type name, :datetime_select end end def test_field_type_returns_time_select - assert_attribute_type 'time', :time_select + assert_field_type 'time', :time_select end def test_field_type_returns_date_select - assert_attribute_type 'date', :date_select + assert_field_type 'date', :date_select end def test_field_type_returns_text_area - assert_attribute_type 'text', :text_area + assert_field_type 'text', :text_area end def test_field_type_returns_check_box - assert_attribute_type 'boolean', :check_box + assert_field_type 'boolean', :check_box end def test_field_type_with_unknown_type_returns_text_field %w(foo bar baz).each do |name| - assert_attribute_type name, :text_field + assert_field_type name, :text_field end end end -- cgit v1.2.3 From 3e84ea014e9f4d0f8d302c9bf8ad04240eec2804 Mon Sep 17 00:00:00 2001 From: Aleksandr Koss Date: Sat, 15 May 2010 20:15:23 +0700 Subject: Fix Hash#index deprecated warning in 1.9.x [#4600 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/tasks/routes.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 42e01d5e51..4bb94d39ea 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -3,7 +3,8 @@ task :routes => :environment do Rails::Application.reload_routes! all_routes = ENV['CONTROLLER'] ? Rails.application.routes.routes.select { |route| route.defaults[:controller] == ENV['CONTROLLER'] } : Rails.application.routes.routes routes = all_routes.collect do |route| - name = Rails.application.routes.named_routes.routes.index(route).to_s + key_method = Hash.method_defined?('key') ? 'key' : 'index' + name = Rails.application.routes.named_routes.routes.send(key_method, route).to_s reqs = route.requirements.empty? ? "" : route.requirements.inspect {:name => name, :verb => route.verb.to_s, :path => route.path, :reqs => reqs} end -- cgit v1.2.3 From fc2480a277fd4753aebf68dcf8787d24e00bd057 Mon Sep 17 00:00:00 2001 From: rohit Date: Sun, 16 May 2010 13:04:46 +0530 Subject: Fixed 1 failure and 2 errors in ActionPack testsuite [#4613 state:commited] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/controller/assert_select_test.rb | 6 +++--- actionpack/test/controller/render_test.rb | 4 ++-- actionpack/test/template/capture_helper_test.rb | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index f1254abcf7..7012c4c9b0 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -211,7 +211,7 @@ class AssertSelectTest < ActionController::TestCase assert_nothing_raised { assert_select "div", "foo" } assert_nothing_raised { assert_select "div", "bar" } assert_nothing_raised { assert_select "div", /\w*/ } - assert_nothing_raised { assert_select "div", /\w*/, :count=>2 } + assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 } assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>"bar" } @@ -276,8 +276,8 @@ class AssertSelectTest < ActionController::TestCase def test_css_select render_html %Q{
    } - assert 2, css_select("div").size - assert 0, css_select("p").size + assert_equal 2, css_select("div").size + assert_equal 0, css_select("p").size end def test_nested_css_select diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 180d5e1a65..52049f2a8a 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1388,7 +1388,7 @@ class EtagRenderTest < ActionController::TestCase def test_render_against_etag_request_should_have_no_content_length_when_match @request.if_none_match = etag_for("hello david") get :render_hello_world_from_variable - assert !@response.headers.has_key?("Content-Length"), @response.headers['Content-Length'] + assert !@response.headers.has_key?("Content-Length") end def test_render_against_etag_request_should_200_when_no_match @@ -1524,4 +1524,4 @@ class LastModifiedRenderTest < ActionController::TestCase get :conditional_hello_with_bangs assert_response :success end -end \ No newline at end of file +end diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index bf541c17d3..9f3d68a639 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -74,7 +74,7 @@ class CaptureHelperTest < ActionView::TestCase @av.output_buffer.force_encoding(alt_encoding) @av.with_output_buffer do - assert alt_encoding, @av.output_buffer.encoding + assert_equal alt_encoding, @av.output_buffer.encoding end end end -- cgit v1.2.3 From 2dc1402417242784a738321e7edd521f8ec7ac83 Mon Sep 17 00:00:00 2001 From: pleax Date: Sat, 15 May 2010 13:53:59 +0400 Subject: added support for html attributes in options_for_select [#2165] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_view/helpers/form_options_helper.rb | 27 ++++++++++- .../test/template/form_options_helper_test.rb | 56 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 8f8db548c3..fe71d2cdf7 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -270,6 +270,15 @@ module ActionView # options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"]) # \n\n # + # You can optionally provide html attributes as the last element of the array. + # + # Examples: + # options_for_select([ "Denmark", ["USA", {:class=>'bold'}], "Sweden" ], ["USA", "Sweden"]) + # \n\n + # + # options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]]) + # \n + # # If you wish to specify disabled option tags, set +selected+ to be a hash, with :disabled being either a value # or array of values to be disabled. In this case, you can use :selected to specify selected option tags. # @@ -291,10 +300,11 @@ module ActionView selected, disabled = extract_selected_and_disabled(selected) options_for_select = container.inject([]) do |options, element| + html_attributes = option_html_attributes(element) text, value = option_text_and_value(element) selected_attribute = ' selected="selected"' if option_value_selected?(value, selected) disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled) - options << %() + options << %() end options_for_select.join("\n").html_safe @@ -486,9 +496,22 @@ module ActionView end private + def option_html_attributes(element) + return "" unless Array === element + html_attributes = [] + element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v| + html_attributes << " #{k}=\"#{html_escape(v.to_s)}\"" + end + html_attributes.join + end + def option_text_and_value(option) # Options are [text, value] pairs or strings used for both. - if !option.is_a?(String) and option.respond_to?(:first) and option.respond_to?(:last) + case + when Array === option + option = option.reject { |e| Hash === e } + [option.first, option.last] + when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last) [option.first, option.last] else [option, option] diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 98503c32fd..19b73aa810 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -767,6 +767,62 @@ class FormOptionsHelperTest < ActionView::TestCase html end + def test_options_for_select_with_element_attributes + assert_dom_equal( + "\n\n\n", + options_for_select([ [ "", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ]) + ) + end + + def test_options_for_select_with_element_attributes_and_selection + assert_dom_equal( + "\n\n", + options_for_select([ "", [ "USA", { :class => 'bold' } ], "Sweden" ], "USA") + ) + end + + def test_options_for_select_with_element_attributes_and_selection_array + assert_dom_equal( + "\n\n", + options_for_select([ "", [ "USA", { :class => 'bold' } ], "Sweden" ], [ "USA", "Sweden" ]) + ) + end + + def test_option_html_attributes_from_without_hash + assert_dom_equal( + "", + option_html_attributes([ 'foo', 'bar' ]) + ) + end + + def test_option_html_attributes_with_single_element_hash + assert_dom_equal( + " class=\"fancy\"", + option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ]) + ) + end + + def test_option_html_attributes_with_multiple_element_hash + assert_dom_equal( + " class=\"fancy\" onclick=\"alert('Hello World');\"", + option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ]) + ) + end + + def test_option_html_attributes_with_multiple_hashes + assert_dom_equal( + " class=\"fancy\" onclick=\"alert('Hello World');\"", + option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ]) + ) + end + + def test_option_html_attributes_with_special_characters + assert_dom_equal( + " onclick=\"alert("<code>")\"", + option_html_attributes([ 'foo', 'bar', { :onclick => %(alert("")) } ]) + ) + end + def test_grouped_collection_select @continents = [ Continent.new("", [Country.new("", ""), Country.new("so", "Somalia")] ), -- cgit v1.2.3 From 6cabc9a61fd78a7cbc06d083a59cb252794e5a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 16 May 2010 14:34:36 +0200 Subject: Add some comments related to Hash method check. --- railties/lib/rails/tasks/routes.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 4bb94d39ea..41619bc1f8 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -3,6 +3,9 @@ task :routes => :environment do Rails::Application.reload_routes! all_routes = ENV['CONTROLLER'] ? Rails.application.routes.routes.select { |route| route.defaults[:controller] == ENV['CONTROLLER'] } : Rails.application.routes.routes routes = all_routes.collect do |route| + # TODO: The :index method is deprecated in 1.9 in favor of :key + # but we don't have :key in 1.8.7. We can remove this check when + # stop supporting 1.8.x key_method = Hash.method_defined?('key') ? 'key' : 'index' name = Rails.application.routes.named_routes.routes.send(key_method, route).to_s reqs = route.requirements.empty? ? "" : route.requirements.inspect -- cgit v1.2.3 From 4ea48f2a9880508a4967be011345fc05570f44c4 Mon Sep 17 00:00:00 2001 From: Hussein Morsy Date: Sun, 16 May 2010 14:50:08 +0200 Subject: Fixed 1 failure in ActionPack testsuite [#4613 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/template/form_helper_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 3893d152a2..d1e1338a17 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -449,8 +449,8 @@ class FormHelperTest < ActionView::TestCase text_area("post", "body", :id => nil) assert_dom_equal check_box("post", "secret", "id" => nil), check_box("post", "secret", :id => nil) - assert_dom_equal radio_button("post", "secret", "id" => nil), - radio_button("post", "secret", :id => nil) + assert_dom_equal radio_button("post", "secret", "0", "id" => nil), + radio_button("post", "secret", "0", :id => nil) end def test_index -- cgit v1.2.3 From f58bdae1f716c71202546c5a40a951b5fc54a591 Mon Sep 17 00:00:00 2001 From: Simon Jefford Date: Sun, 16 May 2010 01:22:30 +0100 Subject: Check blocks are not incorrectly detected when compiling erubis templates [#4575 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/template/handlers/erb.rb | 2 +- actionpack/test/controller/capture_test.rb | 5 +++++ actionpack/test/fixtures/test/proper_block_detection.erb | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 actionpack/test/fixtures/test/proper_block_detection.erb diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 705c2bf82e..237746437a 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -28,7 +28,7 @@ module ActionView src << "@output_buffer.safe_concat('" << escape_text(text) << "');" end - BLOCK_EXPR = /(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ def add_expr_literal(src, code) if code =~ BLOCK_EXPR diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index 06a5af6b32..d1dbd535c4 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -61,6 +61,11 @@ class CaptureTest < ActionController::TestCase assert_equal expected_content_for_output, @response.body end + def test_proper_block_detection + @todo = "some todo" + get :proper_block_detection + end + private def expected_content_for_output "Putting stuff in the title!\n\nGreat stuff!" diff --git a/actionpack/test/fixtures/test/proper_block_detection.erb b/actionpack/test/fixtures/test/proper_block_detection.erb new file mode 100644 index 0000000000..23564dbcee --- /dev/null +++ b/actionpack/test/fixtures/test/proper_block_detection.erb @@ -0,0 +1 @@ +<%= @todo %> -- cgit v1.2.3 From d7a3e65c50c5e8c0a7a37a59d6244c0e91fda629 Mon Sep 17 00:00:00 2001 From: Wijnand Wiersma Date: Sun, 16 May 2010 14:49:40 +0200 Subject: Postgresql doesn't allow to change a string type column to a binary type. Skip this test for postgresql for now. [#4616 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/test/cases/migration_test.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 41e27bd281..768a44f6df 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -860,13 +860,15 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "Tester", Person.new.first_name end - def test_change_column_type_default_should_change - old_columns = Person.connection.columns(Person.table_name, "#{name} Columns") - assert !old_columns.find { |c| c.name == 'data' } - - assert_nothing_raised do - Person.connection.add_column "people", "data", :string, :default => '' - Person.connection.change_column "people", "data", :binary + unless current_adapter?(:PostgreSQLAdapter) + def test_change_column_type_default_should_change + old_columns = Person.connection.columns(Person.table_name, "#{name} Columns") + assert !old_columns.find { |c| c.name == 'data' } + + assert_nothing_raised do + Person.connection.add_column "people", "data", :string, :default => '' + Person.connection.change_column "people", "data", :binary + end end end -- cgit v1.2.3 From fdfebb7782a399839ac9a9e63d5153565d6f88f4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 16 May 2010 10:37:57 -0300 Subject: Make use of assert_equal to test equallity between object assert expects and object and a message of error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4611 state:committed] Signed-off-by: José Valim --- activemodel/test/cases/validations/validates_test.rb | 4 ++-- activemodel/test/cases/validations_test.rb | 2 +- activerecord/test/cases/associations/join_model_test.rb | 2 +- activerecord/test/cases/autosave_association_test.rb | 4 ++-- activerecord/test/cases/finder_test.rb | 4 ++-- activesupport/test/buffered_logger_test.rb | 4 ++-- activesupport/test/caching_test.rb | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index d15fb4a524..b85e491a9c 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -45,7 +45,7 @@ class ValidatesTest < ActiveModel::TestCase Person.validates :karma, :presence => true, :email => true, :if => :condition_is_true person = Person.new person.valid? - assert ["can't be blank", "is not an email"], person.errors[:karma].sort + assert_equal ["can't be blank", "is not an email"], person.errors[:karma].sort end def test_validates_with_unless_shared_conditions @@ -111,4 +111,4 @@ class ValidatesTest < ActiveModel::TestCase person.valid? assert_equal ['Local validator please'], person.errors[:title] end -end \ No newline at end of file +end diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index aa75b8b0d2..af195af080 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -228,7 +228,7 @@ class ValidationsTest < ActiveModel::TestCase t = Topic.new assert t.invalid? - assert ["NO BLANKS HERE"], t.errors[:title] + assert_equal ["NO BLANKS HERE"], t.errors[:title] end def test_list_of_validators_for_model diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 8bdf8bcd55..dca72be4fd 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -289,7 +289,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_array_methods_called_by_method_missing - assert true, authors(:david).categories.any? { |category| category.name == 'General' } + assert authors(:david).categories.any? { |category| category.name == 'General' } assert_nothing_raised { authors(:david).categories.sort } end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 2995cc6f72..5cc5dff633 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -765,7 +765,7 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase @ship.destroy @pirate.reload.catchphrase = "Arr" @pirate.save - assert 'Arr', @pirate.reload.catchphrase + assert_equal 'Arr', @pirate.reload.catchphrase end def test_should_automatically_save_the_associated_model @@ -885,7 +885,7 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase @pirate.destroy @ship.reload.name = "The Vile Insanity" @ship.save - assert 'The Vile Insanity', @ship.reload.name + assert_equal 'The Vile Insanity', @ship.reload.name end def test_should_automatically_save_the_associated_model diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index e78db8969d..c73ad50a71 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -722,10 +722,10 @@ class FinderTest < ActiveRecord::TestCase def test_find_all_by_one_attribute_with_options topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC") - assert topics(:first), topics.last + assert_equal topics(:first), topics.last topics = Topic.find_all_by_content("Have a nice day", :order => "id") - assert topics(:first), topics.first + assert_equal topics(:first), topics.first end def test_find_all_by_array_attribute diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb index 7a0ec2e910..5b072d4102 100644 --- a/activesupport/test/buffered_logger_test.rb +++ b/activesupport/test/buffered_logger_test.rb @@ -73,7 +73,7 @@ class BufferedLoggerTest < Test::Unit::TestCase end @logger.flush - assert !@output.string.empty?, @logger.send(:buffer).size + assert !@output.string.empty?, @logger.send(:buffer).size.to_s end define_method "test_disabling_auto_flush_with_#{disable.inspect}_should_flush_at_max_buffer_size_as_failsafe" do @@ -86,7 +86,7 @@ class BufferedLoggerTest < Test::Unit::TestCase end @logger.info 'there it is.' - assert !@output.string.empty?, @logger.send(:buffer).size + assert !@output.string.empty?, @logger.send(:buffer).size.to_s end end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index d9ff1207e7..3e14c754b7 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -375,7 +375,7 @@ module LocalCacheBehavior def test_local_cache_of_write_nil @cache.with_local_cache do - assert true, @cache.write('foo', nil) + assert @cache.write('foo', nil) assert_nil @cache.read('foo') @peek.write('foo', 'bar') assert_nil @cache.read('foo') @@ -394,7 +394,7 @@ module LocalCacheBehavior @cache.with_local_cache do @cache.write('foo', 'bar') @peek.delete('foo') - assert true, @cache.exist?('foo') + assert @cache.exist?('foo') end end -- cgit v1.2.3 From fa5f93698d33469249d9ca5b122002a617ad39e6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 16 May 2010 10:28:56 -0300 Subject: Added missing require, we are using bind method defined on active_support/core_ext/proc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4610 state:committed] Signed-off-by: José Valim --- actionmailer/lib/action_mailer/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index e1a480c2fb..3c41691af7 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -3,6 +3,7 @@ require 'action_mailer/tmail_compat' require 'action_mailer/collector' require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/proc' module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. -- cgit v1.2.3 From 6c69221985268ada25b4c32360fa4f2403f2156b Mon Sep 17 00:00:00 2001 From: Rizwan Reza Date: Sun, 16 May 2010 19:45:30 +0430 Subject: Takes out stale methods relating to edge_rails_version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/info.rb | 33 --------------------------------- railties/test/rails_info_test.rb | 21 --------------------- 2 files changed, 54 deletions(-) diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index 5a496f6536..e9c3ebe685 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -35,20 +35,6 @@ module Rails end end - def edge_rails_revision(info = git_info) - info[/commit ([a-z0-9-]+)/, 1] || freeze_edge_version - end - - def freeze_edge_version - if File.exist?(rails_vendor_root) - begin - Dir[File.join(rails_vendor_root, 'REVISION_*')].first.scan(/_(\d+)$/).first.first - rescue - Dir[File.join(rails_vendor_root, 'TAG_*')].first.scan(/_(.+)$/).first.first rescue 'unknown' - end - end - end - def to_s column_width = properties.names.map {|name| name.length}.max info = properties.map do |name, value| @@ -75,20 +61,6 @@ module Rails table << '' end end - - protected - def rails_vendor_root - @rails_vendor_root ||= "#{Rails.root}/vendor/rails" - end - - def git_info - env_lang, ENV['LC_ALL'] = ENV['LC_ALL'], 'C' - Dir.chdir(rails_vendor_root) do - silence_stderr { `git log -n 1` } - end - ensure - ENV['LC_ALL'] = env_lang - end end # The Ruby version and platform, e.g. "1.8.2 (powerpc-darwin8.2.0)". @@ -120,11 +92,6 @@ module Rails Rails.configuration.middleware.active.map(&:inspect) end - # The Rails Git revision, if it's checked out into vendor/rails. - property 'Edge Rails revision' do - edge_rails_revision - end - # The application's location on the filesystem. property 'Application root' do File.expand_path(Rails.root) diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index fc28d7e912..1da66062aa 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -14,27 +14,6 @@ class InfoTest < ActiveSupport::TestCase silence_warnings { load 'rails/info.rb' } end - def test_edge_rails_revision_not_set_when_svn_info_is_empty - Rails::Info.property 'Test that this will not be defined' do - Rails::Info.edge_rails_revision '' - end - assert !property_defined?('Test that this will not be defined') - end - - def test_edge_rails_revision_extracted_from_svn_info - Rails::Info.property 'Test Edge Rails revision' do - Rails::Info.edge_rails_revision <<-EOS - commit 420c4b3d8878156d04f45e47050ddc62ae00c68c - Author: David Heinemeier Hansson - Date: Sun Apr 13 17:33:27 2008 -0500 - - Added Rails.public_path to control where HTML and assets are expected to be loaded from -EOS - end - - assert_property 'Test Edge Rails revision', '420c4b3d8878156d04f45e47050ddc62ae00c68c' - end - def test_property_with_block_swallows_exceptions_and_ignores_property assert_nothing_raised do Rails::Info.module_eval do -- cgit v1.2.3 From d61dbce48221b270a5e2d1d35520873c5fdd9677 Mon Sep 17 00:00:00 2001 From: Rizwan Reza Date: Sun, 16 May 2010 20:10:16 +0430 Subject: Take out stale tasks from Actionpack's Rakefile [#4619 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/Rakefile | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/actionpack/Rakefile b/actionpack/Rakefile index b9ace8658a..f3bd7dfc10 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -88,23 +88,4 @@ task :lines do end puts "Total: Lines #{total_lines}, LOC #{total_codelines}" -end - -# Publishing ------------------------------------------------------ - -task :update_scriptaculous do - for js in %w( controls dragdrop effects ) - system("svn export --force http://dev.rubyonrails.org/svn/rails/spinoffs/scriptaculous/src/#{js}.js #{File.dirname(__FILE__)}/lib/action_view/helpers/javascripts/#{js}.js") - end -end - -desc "Updates actionpack to the latest version of the javascript spinoffs" -task :update_js => [ :update_scriptaculous ] - -# Publishing ------------------------------------------------------ - -desc "Publish the API documentation" -task :pdoc => [:rdoc] do - require 'rake/contrib/sshpublisher' - Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload end \ No newline at end of file -- cgit v1.2.3 From 621ee373cbd7f88b0c28d45259b9dc9c43d04e44 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Thu, 8 Apr 2010 18:05:12 +0200 Subject: I have updated the documentation according to ticket #4263 about fixtures and set_fixture_class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/guides/source/active_record_basics.textile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile index 226f1b134b..d81e461e63 100644 --- a/railties/guides/source/active_record_basics.textile +++ b/railties/guides/source/active_record_basics.textile @@ -104,6 +104,14 @@ class Product < ActiveRecord::Base set_table_name "PRODUCT" end +If you do so, you will have to define manually the class name that is hosting the fixtures (class_name.yml) using the +set_fixture_class+ method in your test definition: + +class FunnyJoke < ActiveSupport::TestCase + set_fixture_class :funny_jokes => 'Joke' + fixtures :funny_jokes + ... +end + It's also possible to override the column that should be used as the table's primary key. Use the +ActiveRecord::Base.set_primary_key+ method for that: @@ -201,4 +209,4 @@ Active Record callbacks allow you to attach code to certain events in the life-c h3. Migrations -Rails provides a domain-specific language for managing a database schema called migrations. Migrations are stored in files which are executed against any database that Active Record support using rake. Rails keeps track of which files have been committed to the database and provides rollback features. You can learn more about migrations in the "Active Record Migrations guide":migrations.html \ No newline at end of file +Rails provides a domain-specific language for managing a database schema called migrations. Migrations are stored in files which are executed against any database that Active Record support using rake. Rails keeps track of which files have been committed to the database and provides rollback features. You can learn more about migrations in the "Active Record Migrations guide":migrations.html -- cgit v1.2.3 From b7bdacf1abb71ec2b46ea54893fb881dea36cca8 Mon Sep 17 00:00:00 2001 From: Aleksandr Koss Date: Sun, 16 May 2010 17:52:25 +0100 Subject: Added rails command aliases (s g c db) to reserved words in app generator [#4602 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/rails/app/app_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 0a0b033738..ee44acc2fa 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -149,7 +149,7 @@ module Rails # can change in Ruby 1.8.7 when we FileUtils.cd. RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) - RESERVED_NAMES = %w[generate console server dbconsole + RESERVED_NAMES = %w[generate g console c server s dbconsole db application destroy benchmarker profiler plugin runner test] -- cgit v1.2.3 From 7be58b616337d28dc6f25e9dc26cca935437ec12 Mon Sep 17 00:00:00 2001 From: Simon Jefford Date: Sun, 16 May 2010 17:52:59 +0100 Subject: Tests for new reserved words [#4602 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/generators/app_generator_test.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 8743defe82..3975a39ab1 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -70,8 +70,13 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_name_collision_raises_an_error - content = capture(:stderr){ run_generator [File.join(destination_root, "generate")] } - assert_equal "Invalid application name generate. Please give a name which does not match one of the reserved rails words.\n", content + reserved_words = %w[generate g console c server s dbconsole db + application destroy benchmarker profiler + plugin runner test] + reserved_words.each do |reserved| + content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } + assert_equal "Invalid application name #{reserved}. Please give a name which does not match one of the reserved rails words.\n", content + end end def test_invalid_database_option_raises_an_error -- cgit v1.2.3 From 9ef232a78532f57c6c67b48690ad20b0cc107de8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 16 May 2010 12:07:28 -0300 Subject: Gemfile requires sqlite3-ruby = 1.3.0.beta.2 Signed-off-by: Xavier Noria --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 5a8879d38e..e2d5f1508d 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ group :mri do end # AR -gem "sqlite3-ruby", "= 1.3.0.beta.1", :require => 'sqlite3' +gem "sqlite3-ruby", "= 1.3.0.beta.2", :require => 'sqlite3' group :db do gem "pg", ">= 0.9.0" -- cgit v1.2.3 From 5d0afe75ebd7d88f982a57af84dba1ef62b14c0c Mon Sep 17 00:00:00 2001 From: Nobuhiro IMAI Date: Sun, 16 May 2010 16:12:13 +0200 Subject: prevent to run fixture accessor (e.g. test_foos for TestFoo model) as a test case [#2992 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Wijnand Wiersma Signed-off-by: José Valim --- activerecord/lib/active_record/fixtures.rb | 1 + activerecord/test/cases/fixtures_test.rb | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 4bf33c3856..8099aaa7f7 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -891,6 +891,7 @@ module ActiveRecord instances.size == 1 ? instances.first : instances end + private table_name end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 3ce23209cc..8008b86f81 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -256,6 +256,11 @@ class FixturesWithoutInstantiationTest < ActiveRecord::TestCase def test_fixtures_from_root_yml_without_instantiation assert !defined?(@unknown), "@unknown is not defined" end + + def test_visibility_of_accessor_method + assert_equal false, respond_to?(:topics, false), "should be private method" + assert_equal true, respond_to?(:topics, true), "confirm to respond surely" + end def test_accessor_methods assert_equal "The First Topic", topics(:first).title -- cgit v1.2.3 From f8432108e85c06ab8939869ece0297e72c21e7fe Mon Sep 17 00:00:00 2001 From: Priit Tamboom Date: Sun, 16 May 2010 15:11:07 +0200 Subject: Added nokogiri dependency to Gemfile [#4617 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index e2d5f1508d..e94afc828e 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem "mocha", ">= 0.9.8" group :mri do gem 'json' gem 'yajl-ruby' + gem "nokogiri", ">= 1.4.0" if RUBY_VERSION < '1.9' gem "system_timer" -- cgit v1.2.3 From af0d1a88157942c6e6398dbf73891cff1e152405 Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 15 May 2010 03:47:24 -0700 Subject: Initial work to improve the state of encodings for templates --- actionpack/lib/action_view.rb | 2 + actionpack/lib/action_view/template.rb | 6 ++ .../lib/action_view/template/handlers/erb.rb | 98 ++++++++++++---------- .../lib/active_support/core_ext/string/encoding.rb | 11 +++ activesupport/lib/active_support/ruby/shim.rb | 1 + activesupport/test/core_ext/string_ext_test.rb | 8 ++ 6 files changed, 81 insertions(+), 45 deletions(-) create mode 100644 activesupport/lib/active_support/core_ext/string/encoding.rb diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 5555217ee2..5e3b2ec51b 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -58,6 +58,8 @@ module ActionView end autoload :TestCase, 'action_view/test_case' + + ENCODING_FLAG = "#.*coding[:=]\s*(\S+)[ \t]*" end require 'active_support/i18n' diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index a1a970e2d2..ce249e2a96 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -27,6 +27,12 @@ module ActionView end def initialize(source, identifier, handler, details) + if source.encoding_aware? && source =~ %r{\A#{ENCODING_FLAG}} + # don't snip off the \n to preserve line numbers + source.sub!(/\A[^\n]*/, '') + source.force_encoding($1).encode + end + @source = source @identifier = identifier @handler = handler diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 237746437a..17652d6d1f 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/string/output_safety' +require "action_view/template" require 'erubis' module ActionView @@ -17,65 +18,72 @@ module ActionView end end - module Template::Handlers - class Erubis < ::Erubis::Eruby - def add_preamble(src) - src << "@output_buffer = ActionView::OutputBuffer.new;" - end + class Template + module Handlers + class Erubis < ::Erubis::Eruby + def add_preamble(src) + src << "@output_buffer = ActionView::OutputBuffer.new;" + end - def add_text(src, text) - return if text.empty? - src << "@output_buffer.safe_concat('" << escape_text(text) << "');" - end + def add_text(src, text) + return if text.empty? + src << "@output_buffer.safe_concat('" << escape_text(text) << "');" + end - BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ - def add_expr_literal(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append= ' << code - else - src << '@output_buffer.append= (' << code << ');' + def add_expr_literal(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append= ' << code + else + src << '@output_buffer.append= (' << code << ');' + end end - end - def add_stmt(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append_if_string= ' << code - else - super + def add_stmt(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append_if_string= ' << code + else + super + end end - end - def add_expr_escaped(src, code) - src << '@output_buffer.append= ' << escaped_expr(code) << ';' - end + def add_expr_escaped(src, code) + src << '@output_buffer.append= ' << escaped_expr(code) << ';' + end - def add_postamble(src) - src << '@output_buffer.to_s' + def add_postamble(src) + src << '@output_buffer.to_s' + end end - end - class ERB < Template::Handler - include Compilable + class ERB < Handler + include Compilable - ## - # :singleton-method: - # Specify trim mode for the ERB compiler. Defaults to '-'. - # See ERb documentation for suitable values. - cattr_accessor :erb_trim_mode - self.erb_trim_mode = '-' + ## + # :singleton-method: + # Specify trim mode for the ERB compiler. Defaults to '-'. + # See ERb documentation for suitable values. + cattr_accessor :erb_trim_mode + self.erb_trim_mode = '-' - self.default_format = Mime::HTML + self.default_format = Mime::HTML - cattr_accessor :erb_implementation - self.erb_implementation = Erubis + cattr_accessor :erb_implementation + self.erb_implementation = Erubis - def compile(template) - source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '') - erb = "<% __in_erb_template=true %>#{source}" - result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src - result = "#{$2}\n#{result}" if $2 - result + ENCODING_TAG = Regexp.new("\A(<%#{ENCODING_FLAG}-?%>)[ \t]*") + + def compile(template) + erb = template.source.gsub(ENCODING_TAG, '') + result = self.class.erb_implementation.new( + erb, + :trim => (self.class.erb_trim_mode == "-") + ).src + + result = "#{$2}\n#{result}" if $2 + result + end end end end diff --git a/activesupport/lib/active_support/core_ext/string/encoding.rb b/activesupport/lib/active_support/core_ext/string/encoding.rb new file mode 100644 index 0000000000..d4781bfe0c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/string/encoding.rb @@ -0,0 +1,11 @@ +class String + if defined?(Encoding) && "".respond_to?(:encode) + def encoding_aware? + true + end + else + def encoding_aware? + false + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb index 4a9ac920e8..608b3fe4b9 100644 --- a/activesupport/lib/active_support/ruby/shim.rb +++ b/activesupport/lib/active_support/ruby/shim.rb @@ -15,6 +15,7 @@ require 'active_support/core_ext/enumerable' require 'active_support/core_ext/process/daemon' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/string/interpolation' +require 'active_support/core_ext/string/encoding' require 'active_support/core_ext/rexml' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/file/path' diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 97b08da0e4..09ce39bae2 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -439,6 +439,14 @@ class OutputSafetyTest < ActiveSupport::TestCase test 'emits normal string yaml' do assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) end + + test 'knows whether it is encoding aware' do + if RUBY_VERSION >= "1.9" + assert 'ruby'.encoding_aware? + else + assert !'ruby'.encoding_aware? + end + end end class StringExcludeTest < ActiveSupport::TestCase -- cgit v1.2.3 From 64d109e3539ad600f58536d3ecabd2f87b67fd1c Mon Sep 17 00:00:00 2001 From: wycats Date: Sun, 16 May 2010 10:25:55 +0400 Subject: Significantly improved internal encoding heuristics and support. * Default Encoding.default_internal to UTF-8 * Eliminated the use of file-wide magic comments to coerce code evaluated inside the file * Read templates as BINARY, use default_external or template-wide magic comments inside the Template to set the initial encoding * This means that template handlers in Ruby 1.9 will receive Strings encoded in default_internal (UTF-8 by default) * Create a better Exception for encoding issues, and use it when the template source has bytes that are not compatible with the specified encoding * Allow template handlers to opt-into handling BINARY. If they do so, they need to do some of their own manual encoding work * Added a "Configuration Gotchas" section to the intro Rails Guide instructing users to use UTF-8 for everything * Use config.encoding= in Ruby 1.8, and raise if a value that is an invalid $KCODE value is used Also: * Fixed a few tests that were assert() rather than assert_equal() and were caught by Minitest requiring a String for the message * Fixed a test where an assert_select was misformed, also caught by Minitest being more restrictive * Fixed a test where a Rack response was returning a String rather than an Enumerable --- actionpack/lib/action_view.rb | 6 +- actionpack/lib/action_view/template.rb | 201 +++++++++++++++++---- actionpack/lib/action_view/template/error.rb | 18 ++ .../lib/action_view/template/handlers/erb.rb | 45 ++++- actionpack/lib/action_view/template/resolver.rb | 5 +- actionpack/test/abstract_unit.rb | 4 + actionpack/test/controller/assert_select_test.rb | 4 +- actionpack/test/controller/capture_test.rb | 2 +- actionpack/test/controller/render_test.rb | 4 +- actionpack/test/fixtures/test/content_for.erb | 3 +- .../fixtures/test/content_for_concatenated.erb | 2 +- .../fixtures/test/content_for_with_parameter.erb | 2 +- .../test/non_erb_block_content_for.builder | 2 +- actionpack/test/template/render_test.rb | 10 +- actionpack/test/template/template_test.rb | 128 +++++++++++++ railties/guides/source/getting_started.textile | 21 +++ railties/lib/rails.rb | 1 + railties/lib/rails/application/configuration.rb | 10 +- railties/test/application/configuration_test.rb | 3 +- 19 files changed, 417 insertions(+), 54 deletions(-) create mode 100644 actionpack/test/template/template_test.rb diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 5e3b2ec51b..9f56cca869 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -51,7 +51,9 @@ module ActionView autoload :MissingTemplate, 'action_view/template/error' autoload :ActionViewError, 'action_view/template/error' - autoload :TemplateError, 'action_view/template/error' + autoload :EncodingError, 'action_view/template/error' + autoload :TemplateError, 'action_view/template/error' + autoload :WrongEncodingError, 'action_view/template/error' autoload :TemplateHandler, 'action_view/template' autoload :TemplateHandlers, 'action_view/template' @@ -59,7 +61,7 @@ module ActionView autoload :TestCase, 'action_view/test_case' - ENCODING_FLAG = "#.*coding[:=]\s*(\S+)[ \t]*" + ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' end require 'active_support/i18n' diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index ce249e2a96..5d8ac6b115 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,12 +1,89 @@ -# encoding: utf-8 -# This is so that templates compiled in this file are UTF-8 require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/kernel/singleton_class' module ActionView class Template extend ActiveSupport::Autoload + # === Encodings in ActionView::Template + # + # ActionView::Template is one of a few sources of potential + # encoding issues in Rails. This is because the source for + # templates are usually read from disk, and Ruby (like most + # encoding-aware programming languages) assumes that the + # String retrieved through File IO is encoded in the + # default_external encoding. In Rails, the default + # default_external encoding is UTF-8. + # + # As a result, if a user saves their template as ISO-8859-1 + # (for instance, using a non-Unicode-aware text editor), + # and uses characters outside of the ASCII range, their + # users will see diamonds with question marks in them in + # the browser. + # + # To mitigate this problem, we use a few strategies: + # 1. If the source is not valid UTF-8, we raise an exception + # when the template is compiled to alert the user + # to the problem. + # 2. The user can specify the encoding using Ruby-style + # encoding comments in any template engine. If such + # a comment is supplied, Rails will apply that encoding + # to the resulting compiled source returned by the + # template handler. + # 3. In all cases, we transcode the resulting String to + # the default_internal encoding (which defaults + # to UTF-8). + # + # This means that other parts of Rails can always assume + # that templates are encoded in UTF-8, even if the original + # source of the template was not UTF-8. + # + # From a user's perspective, the easiest thing to do is + # to save your templates as UTF-8. If you do this, you + # do not need to do anything else for things to "just work". + # + # === Instructions for template handlers + # + # The easiest thing for you to do is to simply ignore + # encodings. Rails will hand you the template source + # as the default_internal (generally UTF-8), raising + # an exception for the user before sending the template + # to you if it could not determine the original encoding. + # + # For the greatest simplicity, you can support only + # UTF-8 as the default_internal. This means + # that from the perspective of your handler, the + # entire pipeline is just UTF-8. + # + # === Advanced: Handlers with alternate metadata sources + # + # If you want to provide an alternate mechanism for + # specifying encodings (like ERB does via <%# encoding: ... %>), + # you may indicate that you are willing to accept + # BINARY data by implementing self.accepts_binary? + # on your handler. + # + # If you do, Rails will not raise an exception if + # the template's encoding could not be determined, + # assuming that you have another mechanism for + # making the determination. + # + # In this case, make sure you return a String from + # your handler encoded in the default_internal. Since + # you are handling out-of-band metadata, you are + # also responsible for alerting the user to any + # problems with converting the user's data to + # the default_internal. + # + # To do so, simply raise the raise WrongEncodingError + # as follows: + # + # raise WrongEncodingError.new( + # problematic_string, + # expected_encoding + # ) + eager_autoload do autoload :Error autoload :Handler @@ -16,26 +93,22 @@ module ActionView extend Template::Handlers - attr_reader :source, :identifier, :handler, :virtual_path, :formats + attr_reader :source, :identifier, :handler, :virtual_path, :formats, + :original_encoding - Finalizer = proc do |method_name| + Finalizer = proc do |method_name, mod| proc do - ActionView::CompiledTemplates.module_eval do + mod.module_eval do remove_possible_method method_name end end end def initialize(source, identifier, handler, details) - if source.encoding_aware? && source =~ %r{\A#{ENCODING_FLAG}} - # don't snip off the \n to preserve line numbers - source.sub!(/\A[^\n]*/, '') - source.force_encoding($1).encode - end - - @source = source - @identifier = identifier - @handler = handler + @source = source + @identifier = identifier + @handler = handler + @original_encoding = nil @virtual_path = details[:virtual_path] @method_names = {} @@ -48,7 +121,13 @@ module ActionView # Notice that we use a bang in this instrumentation because you don't want to # consume this in production. This is only slow if it's being listened to. ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do - method_name = compile(locals, view) + if view.is_a?(ActionView::CompiledTemplates) + mod = ActionView::CompiledTemplates + else + mod = view.singleton_class + end + + method_name = compile(locals, view, mod) view.send(method_name, locals, &block) end rescue Exception => e @@ -56,7 +135,7 @@ module ActionView e.sub_template_of(self) raise e else - raise Template::Error.new(self, view.assigns, e) + raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e) end end @@ -81,37 +160,97 @@ module ActionView end private - def compile(locals, view) + # Among other things, this method is responsible for properly setting + # the encoding of the source. Until this point, we assume that the + # source is BINARY data. If no additional information is supplied, + # we assume the encoding is the same as Encoding.default_external. + # + # The user can also specify the encoding via a comment on the first + # line of the template (# encoding: NAME-OF-ENCODING). This will work + # with any template engine, as we process out the encoding comment + # before passing the source on to the template engine, leaving a + # blank line in its stead. + # + # Note that after we figure out the correct encoding, we then + # encode the source into Encoding.default_internal. In general, + # this means that templates will be UTF-8 inside of Rails, + # regardless of the original source encoding. + def compile(locals, view, mod) method_name = build_method_name(locals) return method_name if view.respond_to?(method_name) locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join - code = @handler.call(self) - if code.sub!(/\A(#.*coding.*)\n/, '') - encoding_comment = $1 - elsif defined?(Encoding) && Encoding.respond_to?(:default_external) - encoding_comment = "#coding:#{Encoding.default_external}" + if source.encoding_aware? + if source.sub!(/\A#{ENCODING_FLAG}/, '') + encoding = $1 + else + encoding = Encoding.default_external + end + + # Tag the source with the default external encoding + # or the encoding specified in the file + source.force_encoding(encoding) + + # If the original encoding is BINARY, the actual + # encoding is either stored out-of-band (such as + # in ERB <%# %> style magic comments) or missing. + # This is also true if the original encoding is + # something other than BINARY, but it's invalid. + if source.encoding != Encoding::BINARY && source.valid_encoding? + source.encode! + # If the assumed encoding is incorrect, check to + # see whether the handler accepts BINARY. If it + # does, it has another mechanism for determining + # the true encoding of the String. + elsif @handler.respond_to?(:accepts_binary?) && @handler.accepts_binary? + source.force_encoding(Encoding::BINARY) + # If the handler does not accept BINARY, the + # assumed encoding (either the default_external, + # or the explicit encoding specified by the user) + # is incorrect. We raise an exception here. + else + raise WrongEncodingError.new(source, encoding) + end + + # Don't validate the encoding yet -- the handler + # may treat the String as raw bytes and extract + # the encoding some other way end + code = @handler.call(self) + source = <<-end_src def #{method_name}(local_assigns) - _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code} + _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code} ensure - @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer + @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer end end_src - if encoding_comment - source = "#{encoding_comment}\n#{source}" - line = -1 - else - line = 0 + if source.encoding_aware? + # Handlers should return their source Strings in either the + # default_internal or BINARY. If the handler returns a BINARY + # String, we assume its encoding is the one we determined + # earlier, and encode the resulting source in the default_internal. + if source.encoding == Encoding::BINARY + source.force_encoding(Encoding.default_internal) + end + + # In case we get back a String from a handler that is not in + # BINARY or the default_internal, encode it to the default_internal + source.encode! + + # Now, validate that the source we got back from the template + # handler is valid in the default_internal + unless source.valid_encoding? + raise WrongEncodingError.new(@source, Encoding.default_internal) + end end begin - ActionView::CompiledTemplates.module_eval(source, identifier, line) - ObjectSpace.define_finalizer(self, Finalizer[method_name]) + mod.module_eval(source, identifier, 0) + ObjectSpace.define_finalizer(self, Finalizer[method_name, mod]) method_name rescue Exception => e # errors from template code diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 6866eabf77..d3a53d2147 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -4,6 +4,24 @@ module ActionView class ActionViewError < StandardError #:nodoc: end + class EncodingError < StandardError #:nodoc: + end + + class WrongEncodingError < EncodingError #:nodoc: + def initialize(string, encoding) + @string, @encoding = string, encoding + end + + def message + "Your template was not saved as valid #{@encoding}. Please " \ + "either specify #{@encoding} as the encoding for your template " \ + "in your text editor, or mark the template with its " \ + "encoding by inserting the following as the first line " \ + "of the template:\n\n# encoding: .\n\n" \ + "The source of your template was:\n\n#{@string}" + end + end + class MissingTemplate < ActionViewError #:nodoc: attr_reader :path diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 17652d6d1f..bbf012ab15 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -5,6 +5,11 @@ require 'erubis' module ActionView class OutputBuffer < ActiveSupport::SafeBuffer + def initialize(*) + super + encode! + end + def <<(value) super(value.to_s) end @@ -72,16 +77,50 @@ module ActionView cattr_accessor :erb_implementation self.erb_implementation = Erubis - ENCODING_TAG = Regexp.new("\A(<%#{ENCODING_FLAG}-?%>)[ \t]*") + ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*") + + def self.accepts_binary? + true + end def compile(template) - erb = template.source.gsub(ENCODING_TAG, '') + if template.source.encoding_aware? + # Even though Rails has given us a String tagged with the + # default_internal encoding (likely UTF-8), it is possible + # that the String is actually encoded using a different + # encoding, specified via an ERB magic comment. If the + # String is not actually UTF-8, the regular expression + # engine will (correctly) raise an exception. For now, + # we'll reset the String to BINARY so we can run regular + # expressions against it + template_source = template.source.dup.force_encoding("BINARY") + + # Erubis does not have direct support for encodings. + # As a result, we will extract the ERB-style magic + # comment, give the String to Erubis as BINARY data, + # and then tag the resulting String with the extracted + # encoding later + erb = template_source.gsub(ENCODING_TAG, '') + encoding = $2 + + if !encoding && (template.source.encoding == Encoding::BINARY) + raise WrongEncodingError.new(template_source, Encoding.default_external) + end + end + result = self.class.erb_implementation.new( erb, :trim => (self.class.erb_trim_mode == "-") ).src - result = "#{$2}\n#{result}" if $2 + # If an encoding tag was found, tag the String + # we're returning with that encoding. Otherwise, + # return a BINARY String, which is what ERB + # returns. Note that if a magic comment was + # not specified, we will return the data to + # Rails as BINARY, which will then use its + # own encoding logic to create a UTF-8 String. + result = "\n#{result}".force_encoding(encoding).encode if encoding result end end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index a223b3a55f..ef44925951 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -70,7 +70,10 @@ module ActionView Dir[query].reject { |p| File.directory?(p) }.map do |p| handler, format = extract_handler_and_format(p, formats) - Template.new(File.read(p), File.expand_path(p), handler, + + contents = File.open(p, "rb") {|io| io.read } + + Template.new(contents, File.expand_path(p), handler, :virtual_path => path, :format => format) end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 89ba0990f1..479e62b23d 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -12,6 +12,10 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') +if defined?(Encoding.default_internal) + Encoding.default_internal = "UTF-8" +end + require 'test/unit' require 'abstract_controller' require 'action_controller' diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 7012c4c9b0..4f8ad23174 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -212,12 +212,12 @@ class AssertSelectTest < ActionController::TestCase assert_nothing_raised { assert_select "div", "bar" } assert_nothing_raised { assert_select "div", /\w*/ } assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>/\w*/ } assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } end end diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index d1dbd535c4..47253f22b8 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -68,6 +68,6 @@ class CaptureTest < ActionController::TestCase private def expected_content_for_output - "Putting stuff in the title!\n\nGreat stuff!" + "Putting stuff in the title!\nGreat stuff!" end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 52049f2a8a..2b1f2a27df 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1079,7 +1079,7 @@ class RenderTest < ActionController::TestCase def test_action_talk_to_layout get :action_talk_to_layout - assert_equal "Talking to the layout\n\nAction was here!", @response.body + assert_equal "Talking to the layout\nAction was here!", @response.body end # :addressed: @@ -1096,7 +1096,7 @@ class RenderTest < ActionController::TestCase def test_yield_content_for assert_not_deprecated { get :yield_content_for } - assert_equal "Putting stuff in the title!\n\nGreat stuff!\n", @response.body + assert_equal "Putting stuff in the title!\nGreat stuff!\n", @response.body end def test_overwritting_rendering_relative_file_with_extension diff --git a/actionpack/test/fixtures/test/content_for.erb b/actionpack/test/fixtures/test/content_for.erb index 0e47ca8c3d..1fb829f54c 100644 --- a/actionpack/test/fixtures/test/content_for.erb +++ b/actionpack/test/fixtures/test/content_for.erb @@ -1,2 +1 @@ -<% content_for :title do %>Putting stuff in the title!<% end %> -Great stuff! \ No newline at end of file +<% content_for :title do -%>Putting stuff in the title!<% end -%>Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_concatenated.erb b/actionpack/test/fixtures/test/content_for_concatenated.erb index fb6b4b05d7..e65f629574 100644 --- a/actionpack/test/fixtures/test/content_for_concatenated.erb +++ b/actionpack/test/fixtures/test/content_for_concatenated.erb @@ -1,3 +1,3 @@ <% content_for :title, "Putting stuff " - content_for :title, "in the title!" %> + content_for :title, "in the title!" -%> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_with_parameter.erb b/actionpack/test/fixtures/test/content_for_with_parameter.erb index 57aecbac05..aeb6f73ce0 100644 --- a/actionpack/test/fixtures/test/content_for_with_parameter.erb +++ b/actionpack/test/fixtures/test/content_for_with_parameter.erb @@ -1,2 +1,2 @@ -<% content_for :title, "Putting stuff in the title!" %> +<% content_for :title, "Putting stuff in the title!" -%> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder index a94643561c..d539a425a4 100644 --- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder +++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder @@ -1,4 +1,4 @@ content_for :title do 'Putting stuff in the title!' end -xml << "\nGreat stuff!" +xml << "Great stuff!" diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index d0212024ae..aca96e0a24 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -232,13 +232,13 @@ module RenderTestCases # TODO: Move to deprecated_tests.rb def test_render_with_nested_layout_deprecated assert_deprecated do - assert_equal %(title\n\n\n
    column
    \n
    content
    \n), + assert_equal %(title\n\n
    column
    \n
    content
    \n), @view.render(:file => "test/deprecated_nested_layout.erb", :layout => "layouts/yield") end end def test_render_with_nested_layout - assert_equal %(title\n\n\n
    column
    \n
    content
    \n), + assert_equal %(title\n\n
    column
    \n
    content
    \n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") end @@ -284,7 +284,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase with_external_encoding Encoding::ASCII_8BIT do result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding - assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end @@ -302,7 +302,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message end end end @@ -313,7 +313,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message end end end diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb new file mode 100644 index 0000000000..c4a65d84fc --- /dev/null +++ b/actionpack/test/template/template_test.rb @@ -0,0 +1,128 @@ +require "abstract_unit" + +# These are the normal settings that will be set up by Railties +# TODO: Have these tests support other combinations of these values +Encoding.default_internal = "UTF-8" +Encoding.default_external = "UTF-8" + +class TestERBTemplate < ActiveSupport::TestCase + ERBHandler = ActionView::Template::Handlers::ERB + + class Context + def initialize + @output_buffer = "original" + end + + def hello + "Hello" + end + + def partial + ActionView::Template.new( + "<%= @_virtual_path %>", + "partial", + ERBHandler, + :virtual_path => "partial" + ) + end + + def logger + require "logger" + Logger.new(STDERR) + end + + def my_buffer + @output_buffer + end + end + + def new_template(body = "<%= hello %>", handler = ERBHandler, details = {}) + ActionView::Template.new(body, "hello template", ERBHandler, {:virtual_path => "hello"}) + end + + def render(locals = {}) + @template.render(@obj, locals) + end + + def setup + @obj = Context.new + end + + def test_basic_template + @template = new_template + assert_equal "Hello", render + end + + def test_locals + @template = new_template("<%= my_local %>") + assert_equal "I'm a local", render(:my_local => "I'm a local") + end + + def test_restores_buffer + @template = new_template + assert_equal "Hello", render + assert_equal "original", @obj.my_buffer + end + + def test_virtual_path + @template = new_template("<%= @_virtual_path %>" \ + "<%= partial.render(self, {}) %>" \ + "<%= @_virtual_path %>") + assert_equal "hellopartialhello", render + end + + if "ruby".encoding_aware? + def test_resulting_string_is_utf8 + @template = new_template + assert_equal Encoding::UTF_8, render.encoding + end + + def test_no_magic_comment_word_with_utf_8 + @template = new_template("hello \u{fc}mlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + + # This test ensures that if the default_external + # is set to something other than UTF-8, we don't + # get any errors and get back a UTF-8 String. + def test_default_external_works + Encoding.default_external = "ISO-8859-1" + @template = new_template("hello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + ensure + Encoding.default_external = "UTF-8" + end + + def test_encoding_can_be_specified_with_magic_comment + @template = new_template("# encoding: ISO-8859-1\nhello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "\nhello \u{fc}mlat", render + end + + # TODO: This is currently handled inside ERB. The case of explicitly + # lying about encodings via the normal Rails API should be handled + # inside Rails. + def test_lying_with_magic_comment + assert_raises(ActionView::Template::Error) do + @template = new_template("# encoding: UTF-8\nhello \xFCmlat") + render + end + end + + def test_encoding_can_be_specified_with_magic_comment_in_erb + @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat") + result = render + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + + def test_error_when_template_isnt_valid_utf8 + assert_raises(ActionView::Template::Error, /\xFC/) do + @template = new_template("hello \xFCmlat") + render + end + end + end +end \ No newline at end of file diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 5da7ff7daa..b7301bff20 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1462,11 +1462,32 @@ Rails also comes with built-in help that you can generate using the rake command * Running +rake doc:guides+ will put a full copy of the Rails Guides in the +doc/guides+ folder of your application. Open +doc/guides/index.html+ in your web browser to explore the Guides. * Running +rake doc:rails+ will put a full copy of the API documentation for Rails in the +doc/api+ folder of your application. Open +doc/api/index.html+ in your web browser to explore the API documentation. +h3. Configuration Gotchas + +The easiest way to work with Rails is to store all external data as UTF-8. If you don't, Ruby libraries and Rails will often be able to convert your native data into UTF-8, but this doesn't always work reliably, so you're better off ensuring that all external data is UTF-8. + +If you have made a mistake in this area, the most common symptom is a black diamond with a question mark inside appearing in the browser. Another common symptom is characters like "ü" appearing instead of "ü". Rails takes a number of internal steps to mitigate common causes of these problems that can be automatically detected and corrected. However, if you have external data that is not stored as UTF-8, it can occasionally result in these kinds of issues that cannot be automatically detected by Rails and corrected. + +Two very common sources of data that are not UTF-8: +* Your text editor: Most text editors (such as Textmate), default to saving files as + UTF-8. If your text editor does not, this can result in special characters that you + enter in your templates (such as é) to appear as a diamond with a question mark inside + in the browser. This also applies to your I18N translation files. + Most editors that do not already default to UTF-8 (such as some versions of + Dreamweaver) offer a way to change the default to UTF-8. Do so. +* Your database. Rails defaults to converting data from your database into UTF-8 at + the boundary. However, if your database is not using UTF-8 internally, it may not + be able to store all characters that your users enter. For instance, if your database + is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese + character, the data will be lost forever once it enters the database. If possible, + use UTF-8 as the internal storage of your database. h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2 +* May 16, 2010: Added a section on configuration gotchas to address common encoding + problems that people might have * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com * April 25, 2010: Couple of more minor fixups "Mikel Lindsaar":credits:html#raasdnil * April 1, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 0611b2a9f5..be486ef2ac 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -23,6 +23,7 @@ if RUBY_VERSION < '1.9' $KCODE='u' else Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = Encoding::UTF_8 end module Rails diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 9353fbefef..8afe423973 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,4 +1,5 @@ require 'active_support/deprecation' +require 'active_support/core_ext/string/encoding' require 'rails/engine/configuration' module Rails @@ -27,8 +28,15 @@ module Rails def encoding=(value) @encoding = value - if defined?(Encoding) && Encoding.respond_to?(:default_external=) + if "ruby".encoding_aware? Encoding.default_external = value + Encoding.default_internal = value + else + $KCODE = value + if $KCODE == "NONE" + raise "The value you specified for config.encoding is " \ + "invalid. The possible values are UTF8, SJIS, or EUC" + end end end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index dfc4e2359b..c08bd2ef22 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -180,7 +180,8 @@ module ApplicationTests require "#{app_path}/config/application" unless RUBY_VERSION < '1.9' - assert_equal Encoding.find("utf-8"), Encoding.default_external + assert_equal Encoding::UTF_8, Encoding.default_external + assert_equal Encoding::UTF_8, Encoding.default_internal end end -- cgit v1.2.3 From 821e15e5f2d9ef2aa43918a16cbd00f40c221e95 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 16 May 2010 15:20:52 -0300 Subject: Change on Array extension from rand => random_element [#4555 state:committed] Signed-off-by: Xavier Noria --- .../cases/associations/eager_load_nested_include_test.rb | 14 +++++++------- activerecord/test/cases/named_scope_test.rb | 2 +- .../lib/active_support/core_ext/array/random_access.rb | 12 +++++++++++- activesupport/test/core_ext/array_ext_test.rb | 12 ++++++++---- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index e8db6d5dab..2beb3f8365 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -17,7 +17,7 @@ module Remembered module ClassMethods def remembered; @@remembered ||= []; end - def rand; @@remembered.rand; end + def random_element; @@remembered.random_element; end end end @@ -79,14 +79,14 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase [Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!) end 1.upto(NUM_SIMPLE_OBJS) do - PaintColor.create!(:non_poly_one_id => NonPolyOne.rand.id) - PaintTexture.create!(:non_poly_two_id => NonPolyTwo.rand.id) + PaintColor.create!(:non_poly_one_id => NonPolyOne.random_element.id) + PaintTexture.create!(:non_poly_two_id => NonPolyTwo.random_element.id) end 1.upto(NUM_SHAPE_EXPRESSIONS) do - shape_type = [Circle, Square, Triangle].rand - paint_type = [PaintColor, PaintTexture].rand - ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.rand.id, - :paint_type => paint_type.to_s, :paint_id => paint_type.rand.id) + shape_type = [Circle, Square, Triangle].random_element + paint_type = [PaintColor, PaintTexture].random_element + ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.random_element.id, + :paint_type => paint_type.to_s, :paint_id => paint_type.random_element.id) end end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 9db0e7c143..2007f5492f 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -301,7 +301,7 @@ class NamedScopeTest < ActiveRecord::TestCase end def test_rand_should_select_a_random_object_from_proxy - assert_kind_of Topic, Topic.approved.rand + assert_kind_of Topic, Topic.approved.random_element end def test_should_use_where_in_query_for_named_scope diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb index 343003f6f7..5338836b29 100644 --- a/activesupport/lib/active_support/core_ext/array/random_access.rb +++ b/activesupport/lib/active_support/core_ext/array/random_access.rb @@ -1,6 +1,16 @@ class Array + # This method is deprecated because it masks Kernel#rand within the Array class itself, + # which may be used by a 3rd party library extending Array in turn. See + # + # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555 + # + def rand # :nodoc: + ActiveSupport::Deprecation.warn "Array#rand is deprecated, use random_element instead", caller + random_element + end + # Returns a random element from the array. - def rand + def random_element self[Kernel.rand(length)] end end diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index e7617466c2..ebd6806416 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -358,15 +358,19 @@ class ArrayUniqByTests < Test::Unit::TestCase end end -class ArrayExtRandomTests < Test::Unit::TestCase +class ArrayExtRandomTests < ActiveSupport::TestCase def test_random_element_from_array - assert_nil [].rand + assert_nil [].random_element Kernel.expects(:rand).with(1).returns(0) - assert_equal 'x', ['x'].rand + assert_equal 'x', ['x'].random_element Kernel.expects(:rand).with(3).returns(1) - assert_equal 2, [1, 2, 3].rand + assert_equal 2, [1, 2, 3].random_element + end + + def test_deprecated_rand_on_array + assert_deprecated { [].rand } end end -- cgit v1.2.3 From ade756fe42423033bae8e5aea8f58782f7a6c517 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 16 May 2010 13:52:51 -0700 Subject: Moved encoding work in progress to a feature branch. This reverts commits af0d1a88157942c6e6398dbf73891cff1e152405 and 64d109e3539ad600f58536d3ecabd2f87b67fd1c. --- actionpack/lib/action_view.rb | 6 +- actionpack/lib/action_view/template.rb | 195 +++------------------ actionpack/lib/action_view/template/error.rb | 18 -- .../lib/action_view/template/handlers/erb.rb | 137 +++++---------- actionpack/lib/action_view/template/resolver.rb | 5 +- actionpack/test/abstract_unit.rb | 4 - actionpack/test/controller/assert_select_test.rb | 4 +- actionpack/test/controller/capture_test.rb | 2 +- actionpack/test/controller/render_test.rb | 4 +- actionpack/test/fixtures/test/content_for.erb | 3 +- .../fixtures/test/content_for_concatenated.erb | 2 +- .../fixtures/test/content_for_with_parameter.erb | 2 +- .../test/non_erb_block_content_for.builder | 2 +- actionpack/test/template/render_test.rb | 10 +- actionpack/test/template/template_test.rb | 128 -------------- .../lib/active_support/core_ext/string/encoding.rb | 11 -- activesupport/lib/active_support/ruby/shim.rb | 1 - activesupport/test/core_ext/string_ext_test.rb | 8 - railties/guides/source/getting_started.textile | 21 --- railties/lib/rails.rb | 1 - railties/lib/rails/application/configuration.rb | 10 +- railties/test/application/configuration_test.rb | 3 +- 22 files changed, 89 insertions(+), 488 deletions(-) delete mode 100644 actionpack/test/template/template_test.rb delete mode 100644 activesupport/lib/active_support/core_ext/string/encoding.rb diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 9f56cca869..5555217ee2 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -51,17 +51,13 @@ module ActionView autoload :MissingTemplate, 'action_view/template/error' autoload :ActionViewError, 'action_view/template/error' - autoload :EncodingError, 'action_view/template/error' - autoload :TemplateError, 'action_view/template/error' - autoload :WrongEncodingError, 'action_view/template/error' + autoload :TemplateError, 'action_view/template/error' autoload :TemplateHandler, 'action_view/template' autoload :TemplateHandlers, 'action_view/template' end autoload :TestCase, 'action_view/test_case' - - ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' end require 'active_support/i18n' diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 5d8ac6b115..a1a970e2d2 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,89 +1,12 @@ +# encoding: utf-8 +# This is so that templates compiled in this file are UTF-8 require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/kernel/singleton_class' module ActionView class Template extend ActiveSupport::Autoload - # === Encodings in ActionView::Template - # - # ActionView::Template is one of a few sources of potential - # encoding issues in Rails. This is because the source for - # templates are usually read from disk, and Ruby (like most - # encoding-aware programming languages) assumes that the - # String retrieved through File IO is encoded in the - # default_external encoding. In Rails, the default - # default_external encoding is UTF-8. - # - # As a result, if a user saves their template as ISO-8859-1 - # (for instance, using a non-Unicode-aware text editor), - # and uses characters outside of the ASCII range, their - # users will see diamonds with question marks in them in - # the browser. - # - # To mitigate this problem, we use a few strategies: - # 1. If the source is not valid UTF-8, we raise an exception - # when the template is compiled to alert the user - # to the problem. - # 2. The user can specify the encoding using Ruby-style - # encoding comments in any template engine. If such - # a comment is supplied, Rails will apply that encoding - # to the resulting compiled source returned by the - # template handler. - # 3. In all cases, we transcode the resulting String to - # the default_internal encoding (which defaults - # to UTF-8). - # - # This means that other parts of Rails can always assume - # that templates are encoded in UTF-8, even if the original - # source of the template was not UTF-8. - # - # From a user's perspective, the easiest thing to do is - # to save your templates as UTF-8. If you do this, you - # do not need to do anything else for things to "just work". - # - # === Instructions for template handlers - # - # The easiest thing for you to do is to simply ignore - # encodings. Rails will hand you the template source - # as the default_internal (generally UTF-8), raising - # an exception for the user before sending the template - # to you if it could not determine the original encoding. - # - # For the greatest simplicity, you can support only - # UTF-8 as the default_internal. This means - # that from the perspective of your handler, the - # entire pipeline is just UTF-8. - # - # === Advanced: Handlers with alternate metadata sources - # - # If you want to provide an alternate mechanism for - # specifying encodings (like ERB does via <%# encoding: ... %>), - # you may indicate that you are willing to accept - # BINARY data by implementing self.accepts_binary? - # on your handler. - # - # If you do, Rails will not raise an exception if - # the template's encoding could not be determined, - # assuming that you have another mechanism for - # making the determination. - # - # In this case, make sure you return a String from - # your handler encoded in the default_internal. Since - # you are handling out-of-band metadata, you are - # also responsible for alerting the user to any - # problems with converting the user's data to - # the default_internal. - # - # To do so, simply raise the raise WrongEncodingError - # as follows: - # - # raise WrongEncodingError.new( - # problematic_string, - # expected_encoding - # ) - eager_autoload do autoload :Error autoload :Handler @@ -93,22 +16,20 @@ module ActionView extend Template::Handlers - attr_reader :source, :identifier, :handler, :virtual_path, :formats, - :original_encoding + attr_reader :source, :identifier, :handler, :virtual_path, :formats - Finalizer = proc do |method_name, mod| + Finalizer = proc do |method_name| proc do - mod.module_eval do + ActionView::CompiledTemplates.module_eval do remove_possible_method method_name end end end def initialize(source, identifier, handler, details) - @source = source - @identifier = identifier - @handler = handler - @original_encoding = nil + @source = source + @identifier = identifier + @handler = handler @virtual_path = details[:virtual_path] @method_names = {} @@ -121,13 +42,7 @@ module ActionView # Notice that we use a bang in this instrumentation because you don't want to # consume this in production. This is only slow if it's being listened to. ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do - if view.is_a?(ActionView::CompiledTemplates) - mod = ActionView::CompiledTemplates - else - mod = view.singleton_class - end - - method_name = compile(locals, view, mod) + method_name = compile(locals, view) view.send(method_name, locals, &block) end rescue Exception => e @@ -135,7 +50,7 @@ module ActionView e.sub_template_of(self) raise e else - raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e) + raise Template::Error.new(self, view.assigns, e) end end @@ -160,97 +75,37 @@ module ActionView end private - # Among other things, this method is responsible for properly setting - # the encoding of the source. Until this point, we assume that the - # source is BINARY data. If no additional information is supplied, - # we assume the encoding is the same as Encoding.default_external. - # - # The user can also specify the encoding via a comment on the first - # line of the template (# encoding: NAME-OF-ENCODING). This will work - # with any template engine, as we process out the encoding comment - # before passing the source on to the template engine, leaving a - # blank line in its stead. - # - # Note that after we figure out the correct encoding, we then - # encode the source into Encoding.default_internal. In general, - # this means that templates will be UTF-8 inside of Rails, - # regardless of the original source encoding. - def compile(locals, view, mod) + def compile(locals, view) method_name = build_method_name(locals) return method_name if view.respond_to?(method_name) locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join - if source.encoding_aware? - if source.sub!(/\A#{ENCODING_FLAG}/, '') - encoding = $1 - else - encoding = Encoding.default_external - end - - # Tag the source with the default external encoding - # or the encoding specified in the file - source.force_encoding(encoding) - - # If the original encoding is BINARY, the actual - # encoding is either stored out-of-band (such as - # in ERB <%# %> style magic comments) or missing. - # This is also true if the original encoding is - # something other than BINARY, but it's invalid. - if source.encoding != Encoding::BINARY && source.valid_encoding? - source.encode! - # If the assumed encoding is incorrect, check to - # see whether the handler accepts BINARY. If it - # does, it has another mechanism for determining - # the true encoding of the String. - elsif @handler.respond_to?(:accepts_binary?) && @handler.accepts_binary? - source.force_encoding(Encoding::BINARY) - # If the handler does not accept BINARY, the - # assumed encoding (either the default_external, - # or the explicit encoding specified by the user) - # is incorrect. We raise an exception here. - else - raise WrongEncodingError.new(source, encoding) - end - - # Don't validate the encoding yet -- the handler - # may treat the String as raw bytes and extract - # the encoding some other way - end - code = @handler.call(self) + if code.sub!(/\A(#.*coding.*)\n/, '') + encoding_comment = $1 + elsif defined?(Encoding) && Encoding.respond_to?(:default_external) + encoding_comment = "#coding:#{Encoding.default_external}" + end source = <<-end_src def #{method_name}(local_assigns) - _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code} + _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code} ensure - @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer + @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer end end_src - if source.encoding_aware? - # Handlers should return their source Strings in either the - # default_internal or BINARY. If the handler returns a BINARY - # String, we assume its encoding is the one we determined - # earlier, and encode the resulting source in the default_internal. - if source.encoding == Encoding::BINARY - source.force_encoding(Encoding.default_internal) - end - - # In case we get back a String from a handler that is not in - # BINARY or the default_internal, encode it to the default_internal - source.encode! - - # Now, validate that the source we got back from the template - # handler is valid in the default_internal - unless source.valid_encoding? - raise WrongEncodingError.new(@source, Encoding.default_internal) - end + if encoding_comment + source = "#{encoding_comment}\n#{source}" + line = -1 + else + line = 0 end begin - mod.module_eval(source, identifier, 0) - ObjectSpace.define_finalizer(self, Finalizer[method_name, mod]) + ActionView::CompiledTemplates.module_eval(source, identifier, line) + ObjectSpace.define_finalizer(self, Finalizer[method_name]) method_name rescue Exception => e # errors from template code diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index d3a53d2147..6866eabf77 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -4,24 +4,6 @@ module ActionView class ActionViewError < StandardError #:nodoc: end - class EncodingError < StandardError #:nodoc: - end - - class WrongEncodingError < EncodingError #:nodoc: - def initialize(string, encoding) - @string, @encoding = string, encoding - end - - def message - "Your template was not saved as valid #{@encoding}. Please " \ - "either specify #{@encoding} as the encoding for your template " \ - "in your text editor, or mark the template with its " \ - "encoding by inserting the following as the first line " \ - "of the template:\n\n# encoding: .\n\n" \ - "The source of your template was:\n\n#{@string}" - end - end - class MissingTemplate < ActionViewError #:nodoc: attr_reader :path diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index bbf012ab15..237746437a 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -1,15 +1,9 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/string/output_safety' -require "action_view/template" require 'erubis' module ActionView class OutputBuffer < ActiveSupport::SafeBuffer - def initialize(*) - super - encode! - end - def <<(value) super(value.to_s) end @@ -23,106 +17,65 @@ module ActionView end end - class Template - module Handlers - class Erubis < ::Erubis::Eruby - def add_preamble(src) - src << "@output_buffer = ActionView::OutputBuffer.new;" - end - - def add_text(src, text) - return if text.empty? - src << "@output_buffer.safe_concat('" << escape_text(text) << "');" - end - - BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + module Template::Handlers + class Erubis < ::Erubis::Eruby + def add_preamble(src) + src << "@output_buffer = ActionView::OutputBuffer.new;" + end - def add_expr_literal(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append= ' << code - else - src << '@output_buffer.append= (' << code << ');' - end - end + def add_text(src, text) + return if text.empty? + src << "@output_buffer.safe_concat('" << escape_text(text) << "');" + end - def add_stmt(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append_if_string= ' << code - else - super - end - end + BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ - def add_expr_escaped(src, code) - src << '@output_buffer.append= ' << escaped_expr(code) << ';' + def add_expr_literal(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append= ' << code + else + src << '@output_buffer.append= (' << code << ');' end + end - def add_postamble(src) - src << '@output_buffer.to_s' + def add_stmt(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append_if_string= ' << code + else + super end end - class ERB < Handler - include Compilable - - ## - # :singleton-method: - # Specify trim mode for the ERB compiler. Defaults to '-'. - # See ERb documentation for suitable values. - cattr_accessor :erb_trim_mode - self.erb_trim_mode = '-' - - self.default_format = Mime::HTML - - cattr_accessor :erb_implementation - self.erb_implementation = Erubis - - ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*") + def add_expr_escaped(src, code) + src << '@output_buffer.append= ' << escaped_expr(code) << ';' + end - def self.accepts_binary? - true - end + def add_postamble(src) + src << '@output_buffer.to_s' + end + end - def compile(template) - if template.source.encoding_aware? - # Even though Rails has given us a String tagged with the - # default_internal encoding (likely UTF-8), it is possible - # that the String is actually encoded using a different - # encoding, specified via an ERB magic comment. If the - # String is not actually UTF-8, the regular expression - # engine will (correctly) raise an exception. For now, - # we'll reset the String to BINARY so we can run regular - # expressions against it - template_source = template.source.dup.force_encoding("BINARY") + class ERB < Template::Handler + include Compilable - # Erubis does not have direct support for encodings. - # As a result, we will extract the ERB-style magic - # comment, give the String to Erubis as BINARY data, - # and then tag the resulting String with the extracted - # encoding later - erb = template_source.gsub(ENCODING_TAG, '') - encoding = $2 + ## + # :singleton-method: + # Specify trim mode for the ERB compiler. Defaults to '-'. + # See ERb documentation for suitable values. + cattr_accessor :erb_trim_mode + self.erb_trim_mode = '-' - if !encoding && (template.source.encoding == Encoding::BINARY) - raise WrongEncodingError.new(template_source, Encoding.default_external) - end - end + self.default_format = Mime::HTML - result = self.class.erb_implementation.new( - erb, - :trim => (self.class.erb_trim_mode == "-") - ).src + cattr_accessor :erb_implementation + self.erb_implementation = Erubis - # If an encoding tag was found, tag the String - # we're returning with that encoding. Otherwise, - # return a BINARY String, which is what ERB - # returns. Note that if a magic comment was - # not specified, we will return the data to - # Rails as BINARY, which will then use its - # own encoding logic to create a UTF-8 String. - result = "\n#{result}".force_encoding(encoding).encode if encoding - result - end + def compile(template) + source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '') + erb = "<% __in_erb_template=true %>#{source}" + result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src + result = "#{$2}\n#{result}" if $2 + result end end end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index ef44925951..a223b3a55f 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -70,10 +70,7 @@ module ActionView Dir[query].reject { |p| File.directory?(p) }.map do |p| handler, format = extract_handler_and_format(p, formats) - - contents = File.open(p, "rb") {|io| io.read } - - Template.new(contents, File.expand_path(p), handler, + Template.new(File.read(p), File.expand_path(p), handler, :virtual_path => path, :format => format) end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 479e62b23d..89ba0990f1 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -12,10 +12,6 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') -if defined?(Encoding.default_internal) - Encoding.default_internal = "UTF-8" -end - require 'test/unit' require 'abstract_controller' require 'action_controller' diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 4f8ad23174..7012c4c9b0 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -212,12 +212,12 @@ class AssertSelectTest < ActionController::TestCase assert_nothing_raised { assert_select "div", "bar" } assert_nothing_raised { assert_select "div", /\w*/ } assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>/\w*/ } assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } end end diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index 47253f22b8..d1dbd535c4 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -68,6 +68,6 @@ class CaptureTest < ActionController::TestCase private def expected_content_for_output - "Putting stuff in the title!\nGreat stuff!" + "Putting stuff in the title!\n\nGreat stuff!" end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 2b1f2a27df..52049f2a8a 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1079,7 +1079,7 @@ class RenderTest < ActionController::TestCase def test_action_talk_to_layout get :action_talk_to_layout - assert_equal "Talking to the layout\nAction was here!", @response.body + assert_equal "Talking to the layout\n\nAction was here!", @response.body end # :addressed: @@ -1096,7 +1096,7 @@ class RenderTest < ActionController::TestCase def test_yield_content_for assert_not_deprecated { get :yield_content_for } - assert_equal "Putting stuff in the title!\nGreat stuff!\n", @response.body + assert_equal "Putting stuff in the title!\n\nGreat stuff!\n", @response.body end def test_overwritting_rendering_relative_file_with_extension diff --git a/actionpack/test/fixtures/test/content_for.erb b/actionpack/test/fixtures/test/content_for.erb index 1fb829f54c..0e47ca8c3d 100644 --- a/actionpack/test/fixtures/test/content_for.erb +++ b/actionpack/test/fixtures/test/content_for.erb @@ -1 +1,2 @@ -<% content_for :title do -%>Putting stuff in the title!<% end -%>Great stuff! \ No newline at end of file +<% content_for :title do %>Putting stuff in the title!<% end %> +Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_concatenated.erb b/actionpack/test/fixtures/test/content_for_concatenated.erb index e65f629574..fb6b4b05d7 100644 --- a/actionpack/test/fixtures/test/content_for_concatenated.erb +++ b/actionpack/test/fixtures/test/content_for_concatenated.erb @@ -1,3 +1,3 @@ <% content_for :title, "Putting stuff " - content_for :title, "in the title!" -%> + content_for :title, "in the title!" %> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_with_parameter.erb b/actionpack/test/fixtures/test/content_for_with_parameter.erb index aeb6f73ce0..57aecbac05 100644 --- a/actionpack/test/fixtures/test/content_for_with_parameter.erb +++ b/actionpack/test/fixtures/test/content_for_with_parameter.erb @@ -1,2 +1,2 @@ -<% content_for :title, "Putting stuff in the title!" -%> +<% content_for :title, "Putting stuff in the title!" %> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder index d539a425a4..a94643561c 100644 --- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder +++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder @@ -1,4 +1,4 @@ content_for :title do 'Putting stuff in the title!' end -xml << "Great stuff!" +xml << "\nGreat stuff!" diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index aca96e0a24..d0212024ae 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -232,13 +232,13 @@ module RenderTestCases # TODO: Move to deprecated_tests.rb def test_render_with_nested_layout_deprecated assert_deprecated do - assert_equal %(title\n\n
    column
    \n
    content
    \n), + assert_equal %(title\n\n\n
    column
    \n
    content
    \n), @view.render(:file => "test/deprecated_nested_layout.erb", :layout => "layouts/yield") end end def test_render_with_nested_layout - assert_equal %(title\n\n
    column
    \n
    content
    \n), + assert_equal %(title\n\n\n
    column
    \n
    content
    \n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") end @@ -284,7 +284,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase with_external_encoding Encoding::ASCII_8BIT do result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding - assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end @@ -302,7 +302,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message end end end @@ -313,7 +313,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message end end end diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb deleted file mode 100644 index c4a65d84fc..0000000000 --- a/actionpack/test/template/template_test.rb +++ /dev/null @@ -1,128 +0,0 @@ -require "abstract_unit" - -# These are the normal settings that will be set up by Railties -# TODO: Have these tests support other combinations of these values -Encoding.default_internal = "UTF-8" -Encoding.default_external = "UTF-8" - -class TestERBTemplate < ActiveSupport::TestCase - ERBHandler = ActionView::Template::Handlers::ERB - - class Context - def initialize - @output_buffer = "original" - end - - def hello - "Hello" - end - - def partial - ActionView::Template.new( - "<%= @_virtual_path %>", - "partial", - ERBHandler, - :virtual_path => "partial" - ) - end - - def logger - require "logger" - Logger.new(STDERR) - end - - def my_buffer - @output_buffer - end - end - - def new_template(body = "<%= hello %>", handler = ERBHandler, details = {}) - ActionView::Template.new(body, "hello template", ERBHandler, {:virtual_path => "hello"}) - end - - def render(locals = {}) - @template.render(@obj, locals) - end - - def setup - @obj = Context.new - end - - def test_basic_template - @template = new_template - assert_equal "Hello", render - end - - def test_locals - @template = new_template("<%= my_local %>") - assert_equal "I'm a local", render(:my_local => "I'm a local") - end - - def test_restores_buffer - @template = new_template - assert_equal "Hello", render - assert_equal "original", @obj.my_buffer - end - - def test_virtual_path - @template = new_template("<%= @_virtual_path %>" \ - "<%= partial.render(self, {}) %>" \ - "<%= @_virtual_path %>") - assert_equal "hellopartialhello", render - end - - if "ruby".encoding_aware? - def test_resulting_string_is_utf8 - @template = new_template - assert_equal Encoding::UTF_8, render.encoding - end - - def test_no_magic_comment_word_with_utf_8 - @template = new_template("hello \u{fc}mlat") - assert_equal Encoding::UTF_8, render.encoding - assert_equal "hello \u{fc}mlat", render - end - - # This test ensures that if the default_external - # is set to something other than UTF-8, we don't - # get any errors and get back a UTF-8 String. - def test_default_external_works - Encoding.default_external = "ISO-8859-1" - @template = new_template("hello \xFCmlat") - assert_equal Encoding::UTF_8, render.encoding - assert_equal "hello \u{fc}mlat", render - ensure - Encoding.default_external = "UTF-8" - end - - def test_encoding_can_be_specified_with_magic_comment - @template = new_template("# encoding: ISO-8859-1\nhello \xFCmlat") - assert_equal Encoding::UTF_8, render.encoding - assert_equal "\nhello \u{fc}mlat", render - end - - # TODO: This is currently handled inside ERB. The case of explicitly - # lying about encodings via the normal Rails API should be handled - # inside Rails. - def test_lying_with_magic_comment - assert_raises(ActionView::Template::Error) do - @template = new_template("# encoding: UTF-8\nhello \xFCmlat") - render - end - end - - def test_encoding_can_be_specified_with_magic_comment_in_erb - @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat") - result = render - assert_equal Encoding::UTF_8, render.encoding - assert_equal "hello \u{fc}mlat", render - end - - def test_error_when_template_isnt_valid_utf8 - assert_raises(ActionView::Template::Error, /\xFC/) do - @template = new_template("hello \xFCmlat") - render - end - end - end -end \ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/string/encoding.rb b/activesupport/lib/active_support/core_ext/string/encoding.rb deleted file mode 100644 index d4781bfe0c..0000000000 --- a/activesupport/lib/active_support/core_ext/string/encoding.rb +++ /dev/null @@ -1,11 +0,0 @@ -class String - if defined?(Encoding) && "".respond_to?(:encode) - def encoding_aware? - true - end - else - def encoding_aware? - false - end - end -end \ No newline at end of file diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb index 608b3fe4b9..4a9ac920e8 100644 --- a/activesupport/lib/active_support/ruby/shim.rb +++ b/activesupport/lib/active_support/ruby/shim.rb @@ -15,7 +15,6 @@ require 'active_support/core_ext/enumerable' require 'active_support/core_ext/process/daemon' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/string/interpolation' -require 'active_support/core_ext/string/encoding' require 'active_support/core_ext/rexml' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/file/path' diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 09ce39bae2..97b08da0e4 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -439,14 +439,6 @@ class OutputSafetyTest < ActiveSupport::TestCase test 'emits normal string yaml' do assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) end - - test 'knows whether it is encoding aware' do - if RUBY_VERSION >= "1.9" - assert 'ruby'.encoding_aware? - else - assert !'ruby'.encoding_aware? - end - end end class StringExcludeTest < ActiveSupport::TestCase diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index b7301bff20..5da7ff7daa 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1462,32 +1462,11 @@ Rails also comes with built-in help that you can generate using the rake command * Running +rake doc:guides+ will put a full copy of the Rails Guides in the +doc/guides+ folder of your application. Open +doc/guides/index.html+ in your web browser to explore the Guides. * Running +rake doc:rails+ will put a full copy of the API documentation for Rails in the +doc/api+ folder of your application. Open +doc/api/index.html+ in your web browser to explore the API documentation. -h3. Configuration Gotchas - -The easiest way to work with Rails is to store all external data as UTF-8. If you don't, Ruby libraries and Rails will often be able to convert your native data into UTF-8, but this doesn't always work reliably, so you're better off ensuring that all external data is UTF-8. - -If you have made a mistake in this area, the most common symptom is a black diamond with a question mark inside appearing in the browser. Another common symptom is characters like "ü" appearing instead of "ü". Rails takes a number of internal steps to mitigate common causes of these problems that can be automatically detected and corrected. However, if you have external data that is not stored as UTF-8, it can occasionally result in these kinds of issues that cannot be automatically detected by Rails and corrected. - -Two very common sources of data that are not UTF-8: -* Your text editor: Most text editors (such as Textmate), default to saving files as - UTF-8. If your text editor does not, this can result in special characters that you - enter in your templates (such as é) to appear as a diamond with a question mark inside - in the browser. This also applies to your I18N translation files. - Most editors that do not already default to UTF-8 (such as some versions of - Dreamweaver) offer a way to change the default to UTF-8. Do so. -* Your database. Rails defaults to converting data from your database into UTF-8 at - the boundary. However, if your database is not using UTF-8 internally, it may not - be able to store all characters that your users enter. For instance, if your database - is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese - character, the data will be lost forever once it enters the database. If possible, - use UTF-8 as the internal storage of your database. h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2 -* May 16, 2010: Added a section on configuration gotchas to address common encoding - problems that people might have * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com * April 25, 2010: Couple of more minor fixups "Mikel Lindsaar":credits:html#raasdnil * April 1, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index be486ef2ac..0611b2a9f5 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -23,7 +23,6 @@ if RUBY_VERSION < '1.9' $KCODE='u' else Encoding.default_external = Encoding::UTF_8 - Encoding.default_internal = Encoding::UTF_8 end module Rails diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 8afe423973..9353fbefef 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,5 +1,4 @@ require 'active_support/deprecation' -require 'active_support/core_ext/string/encoding' require 'rails/engine/configuration' module Rails @@ -28,15 +27,8 @@ module Rails def encoding=(value) @encoding = value - if "ruby".encoding_aware? + if defined?(Encoding) && Encoding.respond_to?(:default_external=) Encoding.default_external = value - Encoding.default_internal = value - else - $KCODE = value - if $KCODE == "NONE" - raise "The value you specified for config.encoding is " \ - "invalid. The possible values are UTF8, SJIS, or EUC" - end end end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index c08bd2ef22..dfc4e2359b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -180,8 +180,7 @@ module ApplicationTests require "#{app_path}/config/application" unless RUBY_VERSION < '1.9' - assert_equal Encoding::UTF_8, Encoding.default_external - assert_equal Encoding::UTF_8, Encoding.default_internal + assert_equal Encoding.find("utf-8"), Encoding.default_external end end -- cgit v1.2.3 From 6b4e0cc526f55b5532cf99292c94f0a4db53b16f Mon Sep 17 00:00:00 2001 From: Federico Brubacher Date: Sun, 16 May 2010 07:24:41 -0300 Subject: a cloned object no longer mimics changed flags from creator , plus a test case [#4614 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activemodel/lib/active_model/dirty.rb | 9 +++++---- activerecord/lib/active_record/base.rb | 1 + activerecord/test/cases/dirty_test.rb | 9 +++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index a7ee15a7f6..bbcc345e4b 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -124,11 +124,12 @@ module ActiveModel @previously_changed end + # Map of change attr => original value. + def changed_attributes + @changed_attributes ||= {} + end + private - # Map of change attr => original value. - def changed_attributes - @changed_attributes ||= {} - end # Handle *_changed? for +method_missing+. def attribute_changed?(attr) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 04c474c9a1..c02af328c1 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1467,6 +1467,7 @@ module ActiveRecord #:nodoc: @attributes_cache = {} @new_record = true ensure_proper_type + @changed_attributes = other.changed_attributes.dup if scope = self.class.send(:current_scoped_methods) create_with = scope.scope_for_create diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 7a17ef1ee0..3ea2948f62 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -338,6 +338,15 @@ class DirtyTest < ActiveRecord::TestCase assert !pirate.changed? end + def test_cloned_objects_should_not_copy_dirty_flag_from_creator + pirate = Pirate.create!(:catchphrase => "shiver me timbers") + pirate_clone = pirate.clone + pirate_clone.reset_catchphrase! + pirate.catchphrase = "I love Rum" + assert pirate.catchphrase_changed? + assert !pirate_clone.catchphrase_changed? + end + def test_reverted_changes_are_not_dirty phrase = "shiver me timbers" pirate = Pirate.create!(:catchphrase => phrase) -- cgit v1.2.3