aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Gemfile7
-rw-r--r--RELEASING_RAILS.rdoc31
-rw-r--r--actionpack/CHANGELOG.md14
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb13
-rw-r--r--actionpack/test/template/translation_helper_test.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb29
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb18
-rw-r--r--activerecord/lib/active_record/session_store.rb7
-rw-r--r--activerecord/test/cases/migration_test.rb174
-rw-r--r--activesupport/lib/active_support/dependencies.rb2
-rw-r--r--railties/guides/source/migrations.textile2
12 files changed, 85 insertions, 219 deletions
diff --git a/.gitignore b/.gitignore
index aa14cee911..52a431867c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
# Check out http://help.github.com/ignore-files/ for how to set that up.
debug.log
+.Gemfile
/.bundle
/.rbenv-version
/.rvmrc
diff --git a/Gemfile b/Gemfile
index 97605e32b5..b0fbb3b310 100644
--- a/Gemfile
+++ b/Gemfile
@@ -36,13 +36,11 @@ gem "memcache-client", ">= 1.8.5"
platforms :mri_18 do
gem "system_timer"
- gem "ruby-debug", ">= 0.10.3" unless ENV['TRAVIS']
gem "json"
end
-platforms :mri_19 do
- gem "ruby-debug19", :require => "ruby-debug" unless ENV['TRAVIS'] || RUBY_VERSION >= "2.0"
-end
+# Add your own local bundler stuff
+instance_eval File.read ".Gemfile" if File.exists? ".Gemfile"
platforms :mri do
group :test do
@@ -69,7 +67,6 @@ platforms :ruby do
end
platforms :jruby do
- gem "ruby-debug", ">= 0.10.3"
gem "json"
gem "activerecord-jdbcsqlite3-adapter", ">= 1.2.0"
diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc
index 1dfcfe2488..3f05e97b91 100644
--- a/RELEASING_RAILS.rdoc
+++ b/RELEASING_RAILS.rdoc
@@ -205,3 +205,34 @@ There are two simple steps for fixing the CI:
2. Fix it
Repeat these steps until the CI is green.
+
+=== Manually trigger docs generation
+
+We have a post-receive hook in GitHub that calls the docs server on pushes.
+Triggers generation and publication of edge docs, updates the contrib app,
+and generates and publishes stable docs if a new stable tag is detected.
+
+The hook unfortunately is not invoked by tag pushing, so once the new stable
+tag has been pushed to origin, please run
+
+ curl -X POST -d '' http://rails-hooks.hashref.com/rails-master-hook
+
+You should see something like this:
+
+ Rails master hook tasks scheduled:
+
+ * updates the local checkout
+ * updates Rails Contributors
+ * generates and publishes edge docs
+
+ If a new stable tag is detected it also
+
+ * generates and publishes stable docs
+
+ This needs typically a few minutes.
+
+Note you do not need to specify the tag, the docs server figures it out.
+
+Also, don't worry if you call that multiple times or the hook is triggered
+again by some immediate regular push, if the scripts are running new calls
+are just queued (in a queue of size 1).
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 4c265c41d8..9d847c763b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -64,6 +64,20 @@
## Rails 3.1.2 (unreleased) ##
+* Fix XSS security vulnerability in the `translate` helper method. When using interpolation
+ in combination with HTML-safe translations, the interpolated input would not get HTML
+ escaped. *GH 3664*
+
+ Before:
+
+ translate('foo_html', :something => '<script>') # => "...<script>..."
+
+ After:
+
+ translate('foo_html', :something => '<script>') # => "...&lt;script&gt;..."
+
+ *Sergey Nartimov*
+
* Upgrade sprockets dependency to ~> 2.1.0
* Ensure that the format isn't applied twice to the cache key, else it becomes impossible
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index be64dc823e..42726f888c 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -45,11 +45,16 @@ module ActionView
# you know what kind of output to expect when you call translate in a template.
def translate(key, options = {})
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
- translation = I18n.translate(scope_key_by_partial(key), options)
- if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
- translation.html_safe
+ if html_safe_translation_key?(key)
+ html_safe_options = options.dup
+ options.except(*I18n::RESERVED_KEYS).each do |name, value|
+ html_safe_options[name] = ERB::Util.html_escape(value.to_s)
+ end
+ translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
+
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
else
- translation
+ I18n.translate(scope_key_by_partial(key), options)
end
end
alias :t :translate
diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb
index cd9f54e04c..cabb29cfad 100644
--- a/actionpack/test/template/translation_helper_test.rb
+++ b/actionpack/test/template/translation_helper_test.rb
@@ -17,6 +17,7 @@ class TranslationHelperTest < ActiveSupport::TestCase
:hello => '<a>Hello World</a>',
:html => '<a>Hello World</a>',
:hello_html => '<a>Hello World</a>',
+ :interpolated_html => '<a>Hello %{word}</a>',
:array_html => %w(foo bar),
:array => %w(foo bar)
}
@@ -83,6 +84,11 @@ class TranslationHelperTest < ActiveSupport::TestCase
assert translate(:'translations.hello_html').html_safe?
end
+ def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
+ assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>')
+ assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>"))
+ end
+
def test_translation_returning_an_array_ignores_html_suffix
assert_equal ["foo", "bar"], translate(:'translations.array_html')
end
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 7742f32213..faa42e2d19 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -155,17 +155,11 @@ module ActiveRecord
# )
#
# See also TableDefinition#column for details on how to create columns.
- def create_table(table_name, options = {}, &blk)
+ def create_table(table_name, options = {})
td = table_definition
td.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
- if block_given?
- if blk.arity == 1
- yield td
- else
- td.instance_eval(&blk)
- end
- end
+ yield td if block_given?
if options[:force] && table_exists?(table_name)
drop_table(table_name)
@@ -242,19 +236,14 @@ module ActiveRecord
#
# See also Table for details on
# all of the various column transformation
- def change_table(table_name, options = {}, &blk)
- bulk_change = supports_bulk_alter? && options[:bulk]
- recorder = bulk_change ? ActiveRecord::Migration::CommandRecorder.new(self) : self
- table = Table.new(table_name, recorder)
-
- if block_given?
- if blk.arity == 1
- yield table
- else
- table.instance_eval(&blk)
- end
+ def change_table(table_name, options = {})
+ if supports_bulk_alter? && options[:bulk]
+ recorder = ActiveRecord::Migration::CommandRecorder.new(self)
+ yield Table.new(table_name, recorder)
+ bulk_change_table(table_name, recorder.commands)
+ else
+ yield Table.new(table_name, self)
end
- bulk_change_table(table_name, recorder.commands) if bulk_change
end
# Renames a table.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 35df0a1542..bc3804b3d9 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -480,30 +480,28 @@ module ActiveRecord
drop_table(from)
end
- def copy_table(from, to, options = {}, &block) #:nodoc:
- from_columns, from_primary_key = columns(from), primary_key(from)
- options = options.merge(:id => (!from_columns.detect {|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
- table_definition = nil
+ def copy_table(from, to, options = {}) #:nodoc:
+ options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
create_table(to, options) do |definition|
- table_definition = definition
- from_columns.each do |column|
+ @definition = definition
+ columns(from).each do |column|
column_name = options[:rename] ?
(options[:rename][column.name] ||
options[:rename][column.name.to_sym] ||
column.name) : column.name
- table_definition.column(column_name, column.type,
+ @definition.column(column_name, column.type,
:limit => column.limit, :default => column.default,
:precision => column.precision, :scale => column.scale,
:null => column.null)
end
- table_definition.primary_key from_primary_key if from_primary_key
- table_definition.instance_eval(&block) if block
+ @definition.primary_key(primary_key(from)) if primary_key(from)
+ yield @definition if block_given?
end
copy_table_indexes(from, to, options[:rename] || {})
copy_table_contents(from, to,
- table_definition.columns.map {|column| column.name},
+ @definition.columns.map {|column| column.name},
options[:rename] || {})
end
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index 92550c7efc..76c37cc367 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -64,13 +64,12 @@ module ActiveRecord
end
def create_table!
- id_col_name, data_col_name = session_id_column, data_column_name
connection_pool.clear_table_cache!(table_name)
connection.create_table(table_name) do |t|
- t.string id_col_name, :limit => 255
- t.text data_col_name
+ t.string session_id_column, :limit => 255
+ t.text data_column_name
end
- connection.add_index table_name, id_col_name, :unique => true
+ connection.add_index table_name, session_id_column, :unique => true
end
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 75eb9c2bce..3e219f2a49 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -1639,180 +1639,6 @@ if ActiveRecord::Base.connection.supports_migrations?
end
- class SexyMigrationsTest < ActiveRecord::TestCase
- def test_references_column_type_adds_id
- with_new_table do |t|
- t.expects(:column).with('customer_id', :integer, {})
- t.references :customer
- end
- end
-
- def test_references_column_type_with_polymorphic_adds_type
- with_new_table do |t|
- t.expects(:column).with('taggable_type', :string, {})
- t.expects(:column).with('taggable_id', :integer, {})
- t.references :taggable, :polymorphic => true
- end
- end
-
- def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
- with_new_table do |t|
- t.expects(:column).with('taggable_type', :string, {:null => false})
- t.expects(:column).with('taggable_id', :integer, {:null => false})
- t.references :taggable, :polymorphic => true, :null => false
- end
- end
-
- def test_belongs_to_works_like_references
- with_new_table do |t|
- t.expects(:column).with('customer_id', :integer, {})
- t.belongs_to :customer
- end
- end
-
- def test_timestamps_creates_updated_at_and_created_at
- with_new_table do |t|
- t.expects(:column).with(:created_at, :datetime, kind_of(Hash))
- t.expects(:column).with(:updated_at, :datetime, kind_of(Hash))
- t.timestamps
- end
- end
-
- def test_integer_creates_integer_column
- with_new_table do |t|
- t.expects(:column).with(:foo, 'integer', {})
- t.expects(:column).with(:bar, 'integer', {})
- t.integer :foo, :bar
- end
- end
-
- def test_string_creates_string_column
- with_new_table do |t|
- t.expects(:column).with(:foo, 'string', {})
- t.expects(:column).with(:bar, 'string', {})
- t.string :foo, :bar
- end
- end
-
- if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLite3Adapter) || current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter)
- def test_xml_creates_xml_column
- type = current_adapter?(:PostgreSQLAdapter) ? 'xml' : :text
-
- with_new_table do |t|
- t.expects(:column).with(:data, type, {})
- t.xml :data
- end
- end
- else
- def test_xml_creates_xml_column
- with_new_table do |t|
- assert_raises(NotImplementedError) do
- t.xml :data
- end
- end
- end
- end
-
- protected
- def with_new_table
- Person.connection.create_table :delete_me, :force => true do |t|
- yield t
- end
- ensure
- Person.connection.drop_table :delete_me rescue nil
- end
-
- end # SexyMigrationsTest
-
- class SexierMigrationsTest < ActiveRecord::TestCase
- def test_create_table_with_column_without_block_parameter
- Person.connection.create_table :testings, :force => true do
- column :foo, :string
- end
- assert Person.connection.column_exists?(:testings, :foo, :string)
- ensure
- Person.connection.drop_table :testings rescue nil
- end
-
- def test_create_table_with_sexy_column_without_block_parameter
- Person.connection.create_table :testings, :force => true do
- integer :bar
- end
- assert Person.connection.column_exists?(:testings, :bar, :integer)
- ensure
- Person.connection.drop_table :testings rescue nil
- end
-
- def test_create_table_should_not_have_mixed_syntax
- assert_raise(NoMethodError) do
- Person.connection.create_table :testings, :force => true do |t|
- t.string :foo
- integer :bar
- end
- end
- assert_raise(NameError) do
- Person.connection.create_table :testings, :force => true do
- t.string :foo
- integer :bar
- end
- end
- end
-
- def test_change_table_without_block_parameter_no_bulk
- Person.connection.create_table :testings, :force => true do
- string :foo
- end
- assert Person.connection.column_exists?(:testings, :foo, :string)
-
- Person.connection.change_table :testings do
- remove :foo
- integer :bar
- end
-
- assert_equal %w(bar id), Person.connection.columns(:testings).map { |c| c.name }.sort
- ensure
- Person.connection.drop_table :testings rescue nil
- end
-
- if ActiveRecord::Base.connection.supports_bulk_alter?
- def test_change_table_without_block_parameter_with_bulk
- Person.connection.create_table :testings, :force => true do
- string :foo
- end
- assert Person.connection.column_exists?(:testings, :foo, :string)
-
- assert_queries(1) do
- Person.connection.change_table(:testings, :bulk => true) do
- integer :bar
- string :foo_bar
- end
- end
-
- assert_equal %w(bar foo foo_bar id), Person.connection.columns(:testings).map { |c| c.name }.sort
- ensure
- Person.connection.drop_table :testings rescue nil
- end
- end
-
- def test_change_table_should_not_have_mixed_syntax
- Person.connection.create_table :testings, :force => true do
- string :foo
- end
- assert_raise(NoMethodError) do
- Person.connection.change_table :testings do |t|
- t.remove :foo
- integer :bar
- end
- end
- assert_raise(NameError) do
- Person.connection.change_table :testings do
- t.remove :foo
- integer :bar
- end
- end
- end
- end # SexierMigrationsTest
-
class MigrationLoggerTest < ActiveRecord::TestCase
def test_migration_should_be_run_without_logger
previous_logger = ActiveRecord::Base.logger
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index b3ac271778..db90de4682 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -428,7 +428,7 @@ module ActiveSupport #:nodoc:
end
# Attempt to autoload the provided module name by searching for a directory
- # matching the expect path suffix. If found, the module is created and assigned
+ # matching the expected path suffix. If found, the module is created and assigned
# to +into+'s constants with the name +const_name+. Provided that the directory
# was loaded from a reloadable base path, it is added to the set of constants
# that are to be unloaded.
diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile
index 23e36b39f9..5b52a93853 100644
--- a/railties/guides/source/migrations.textile
+++ b/railties/guides/source/migrations.textile
@@ -658,7 +658,7 @@ In many ways this is exactly what it is. This file is created by inspecting the
There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers, or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. If you are using features like this, then you should set the schema format to +:sql+.
-Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the +db:structure:dump+ Rake task) into +db/#{Rails.env}_structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading these schemas is simply a question of executing the SQL statements they contain. By definition, this will create a perfect copy of the database's structure. Using the +:sql+ schema format will, however, prevent loading the schema into a RDBMS other than the one used to create it.
+Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the +db:structure:dump+ Rake task) into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading these schemas is simply a question of executing the SQL statements they contain. By definition, this will create a perfect copy of the database's structure. Using the +:sql+ schema format will, however, prevent loading the schema into a RDBMS other than the one used to create it.
h4. Schema Dumps and Source Control