diff options
-rw-r--r-- | Gemfile.lock | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixture_set/file.rb | 7 | ||||
-rw-r--r-- | activerecord/test/cases/fixtures_test.rb | 14 | ||||
-rw-r--r-- | activerecord/test/fixtures/naked/yml/courses_with_invalid_key.yml | 3 | ||||
-rw-r--r-- | activesupport/lib/active_support/callbacks.rb | 12 | ||||
-rw-r--r-- | activesupport/test/callbacks_test.rb | 83 | ||||
-rw-r--r-- | guides/source/generators.md | 20 | ||||
-rw-r--r-- | guides/source/security.md | 2 |
8 files changed, 119 insertions, 24 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index eb14330c2b..0763efc001 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -162,7 +162,7 @@ GEM coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.10.0) + coffee-script-source (1.12.2) concurrent-ruby (1.0.2) connection_pool (2.2.0) cookiejar (0.3.3) diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb index 5ba354d758..6cf2e01179 100644 --- a/activerecord/lib/active_record/fixture_set/file.rb +++ b/activerecord/lib/active_record/fixture_set/file.rb @@ -66,10 +66,13 @@ module ActiveRecord # Validate our unmarshalled data. def validate(data) unless Hash === data || YAML::Omap === data - raise Fixture::FormatError, "fixture is not a hash" + raise Fixture::FormatError, "fixture is not a hash: #{@file}" end - raise Fixture::FormatError unless data.all? { |name, row| Hash === row } + invalid = data.reject { |_, row| Hash === row } + if invalid.any? + raise Fixture::FormatError, "fixture key is not a hash: #{@file}, keys: #{invalid.keys.inspect}" + end data end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index f3d0e4a1b1..ea3e8d7727 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -211,9 +211,19 @@ class FixturesTest < ActiveRecord::TestCase end def test_dirty_dirty_yaml_file - assert_raise(ActiveRecord::Fixture::FormatError) do - ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, FIXTURES_ROOT + "/naked/yml/courses") + fixture_path = FIXTURES_ROOT + "/naked/yml/courses" + error = assert_raise(ActiveRecord::Fixture::FormatError) do + ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) end + assert_equal "fixture is not a hash: #{fixture_path}.yml", error.to_s + end + + def test_yaml_file_with_one_invalid_fixture + fixture_path = FIXTURES_ROOT + "/naked/yml/courses_with_invalid_key" + error = assert_raise(ActiveRecord::Fixture::FormatError) do + ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) + end + assert_equal "fixture key is not a hash: #{fixture_path}.yml, keys: [\"two\"]", error.to_s end def test_yaml_file_with_invalid_column diff --git a/activerecord/test/fixtures/naked/yml/courses_with_invalid_key.yml b/activerecord/test/fixtures/naked/yml/courses_with_invalid_key.yml new file mode 100644 index 0000000000..6f9da79b45 --- /dev/null +++ b/activerecord/test/fixtures/naked/yml/courses_with_invalid_key.yml @@ -0,0 +1,3 @@ +one: + id: 1 +two: ['not a hash'] diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index af8ddb176f..e6c79f2a38 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -109,16 +109,22 @@ module ActiveSupport invoke_sequence = Proc.new do skipped = nil while true - current, next_sequence = next_sequence, next_sequence.nested + current = next_sequence current.invoke_before(env) if current.final? env.value = !env.halted && (!block_given? || yield) elsif current.skip?(env) (skipped ||= []) << current + next_sequence = next_sequence.nested next else - target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) - target.send(method, *arguments, &block) + next_sequence = next_sequence.nested + begin + target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) + target.send(method, *arguments, &block) + ensure + next_sequence = current + end end current.invoke_after(env) skipped.pop.invoke_after(env) while skipped && skipped.first diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index aadc40ab84..22f66978f8 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -224,10 +224,51 @@ module CallbacksTest define_callbacks :save end - class AroundPerson < MySuper + class MySlate < MySuper attr_reader :history attr_accessor :save_fails + def initialize + @history = [] + end + + def save + run_callbacks :save do + raise "inside save" if save_fails + @history << "running" + end + end + + def no; false; end + def yes; true; end + + def method_missing(sym, *) + case sym + when /^log_(.*)/ + @history << $1 + nil + when /^wrap_(.*)/ + @history << "wrap_#$1" + yield + @history << "unwrap_#$1" + nil + when /^double_(.*)/ + @history << "first_#$1" + yield + @history << "second_#$1" + yield + @history << "third_#$1" + else + super + end + end + + def respond_to_missing?(sym) + sym =~ /^(log|wrap)_/ || super + end + end + + class AroundPerson < MySlate set_callback :save, :before, :nope, if: :no set_callback :save, :before, :nope, unless: :yes set_callback :save, :after, :tweedle @@ -242,9 +283,6 @@ module CallbacksTest set_callback :save, :around, :w0tno, if: :no set_callback :save, :around, :tweedle_deedle - def no; false; end - def yes; true; end - def nope @history << "boom" end @@ -283,17 +321,6 @@ module CallbacksTest yield @history << "tweedle deedle post" end - - def initialize - @history = [] - end - - def save - run_callbacks :save do - raise "inside save" if save_fails - @history << "running" - end - end end class AroundPersonResult < MySuper @@ -408,6 +435,32 @@ module CallbacksTest end end + class DoubleYieldTest < ActiveSupport::TestCase + class DoubleYieldModel < MySlate + set_callback :save, :around, :wrap_outer + set_callback :save, :around, :double_trouble + set_callback :save, :around, :wrap_inner + end + + def test_double_save + double = DoubleYieldModel.new + double.save + assert_equal [ + "wrap_outer", + "first_trouble", + "wrap_inner", + "running", + "unwrap_inner", + "second_trouble", + "wrap_inner", + "running", + "unwrap_inner", + "third_trouble", + "unwrap_outer", + ], double.history + end + end + class CallStackTest < ActiveSupport::TestCase def test_tidy_call_stack around = AroundPerson.new diff --git a/guides/source/generators.md b/guides/source/generators.md index 32bbdc554a..56edfcc8ae 100644 --- a/guides/source/generators.md +++ b/guides/source/generators.md @@ -451,6 +451,26 @@ $ rails new thud -m https://gist.github.com/radar/722911/raw/ Whilst the final section of this guide doesn't cover how to generate the most awesome template known to man, it will take you through the methods available at your disposal so that you can develop it yourself. These same methods are also available for generators. +Adding Command Line Arguments +----------------------------- +Rails generators can be easily modified to accept custom command line arguments. This functionality comes from [Thor](http://www.rubydoc.info/github/erikhuda/thor/master/Thor/Base/ClassMethods#class_option-instance_method): + +``` +class_option :scope, type: :string, default: 'read_products' +``` + +Now our generator can be invoked as follows: + +```bash +rails generate initializer --scope write_products +``` + +The command line arguments are accessed through the `options` method inside the generator class. e.g: + +```ruby +@scope = options['scope'] +``` + Generator methods ----------------- diff --git a/guides/source/security.md b/guides/source/security.md index bb67eb75d9..a81a782cf2 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -377,7 +377,7 @@ In 2007 there was the first tailor-made trojan which stole information from an I Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer. -Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface. +Refer to the Injection section for countermeasures against XSS. **CSRF** Cross-Site Request Forgery (CSRF), also known as Cross-Site Reference Forgery (XSRF), is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface. |