Permalink
Browse files

Merge

  • Loading branch information...
2 parents f6bbc3f + f6d0eda commit 09aeee7247682178868241d446051696570e6e12 @dhh dhh committed Dec 18, 2012
Showing with 374 additions and 49 deletions.
  1. +4 −0 actionpack/CHANGELOG.md
  2. +1 −1 actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
  3. +3 −1 actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
  4. +16 −0 actionpack/lib/action_dispatch/middleware/templates/routes/_route.html.erb
  5. +56 −0 actionpack/lib/action_dispatch/middleware/templates/routes/_route_wrapper.html.erb
  6. +6 −2 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  7. +23 −1 actionpack/test/template/asset_tag_helper_test.rb
  8. +9 −0 activerecord/CHANGELOG.md
  9. +1 −0 activerecord/lib/active_record/connection_adapters/column.rb
  10. +30 −0 activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
  11. +11 −0 activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
  12. +10 −0 activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
  13. +8 −0 activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
  14. +15 −4 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  15. +33 −32 activerecord/lib/active_record/validations/uniqueness.rb
  16. +104 −0 activerecord/test/cases/adapters/postgresql/intrange_test.rb
  17. +20 −3 activerecord/test/cases/validations/uniqueness_validation_test.rb
  18. +11 −1 activerecord/test/schema/postgresql_specific_schema.rb
  19. +6 −0 railties/CHANGELOG.md
  20. +2 −2 railties/lib/rails/info_controller.rb
  21. +4 −1 railties/lib/rails/templates/rails/info/routes.html.erb
  22. +1 −1 railties/test/rails_info_controller_test.rb
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* Handle `:protocol` option in `stylesheet_link_tag` and `javascript_include_tag`
+
+ *Vasiliy Ermolovich*
+
* Clear url helper methods when routes are reloaded. *Andrew White*
* Fix a bug in `ActionDispatch::Request#raw_post` that caused `env['rack.input']`
@@ -87,7 +87,7 @@ def formatted_routes(exception)
return false unless @routes_app.respond_to?(:routes)
if exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)
inspector = ActionDispatch::Routing::RoutesInspector.new
- inspector.format(@routes_app.routes.routes).join("\n")
+ inspector.collect_routes(@routes_app.routes.routes)
end
end
end
@@ -20,4 +20,6 @@
Routes match in priority from top to bottom
</p>
-<p><pre><%= @routes %></pre></p>
+<%= render layout: "routes/route_wrapper" do %>
+ <%= render partial: "routes/route", collection: @routes %>
+<% end %>
@@ -0,0 +1,16 @@
+<tr class='route_row' data-helper='path'>
+ <td data-route-name='<%= route[:name] %>'>
+ <% if route[:name].present? %>
+ <%= route[:name] %><span class='helper'>_path</span>
+ <% end %>
+ </td>
+ <td data-route-verb='<%= route[:verb] %>'>
+ <%= route[:verb] %>
+ </td>
+ <td data-route-path='<%= route[:path] %>'>
+ <%= route[:path] %>
+ </td>
+ <td data-route-reqs='<%= route[:reqs] %>'>
+ <%= route[:reqs] %>
+ </td>
+</tr>
@@ -0,0 +1,56 @@
+<style type='text/css'>
+ #route_table td {padding: 0 30px;}
+ #route_table {margin: 0 auto 0;}
+</style>
+
+<table id='route_table' class='route_table'>
+ <thead>
+ <tr>
+ <th>Helper<br />
+ <%= link_to "Path", "#", 'data-route-helper' => '_path',
+ title: "Returns a relative path (without the http or domain)" %> /
+ <%= link_to "Url", "#", 'data-route-helper' => '_url',
+ title: "Returns an absolute url (with the http and domain)" %>
+ </th>
+ <th>HTTP Verb</th>
+ <th>Path</th>
+ <th>Controller#Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%= yield %>
+ </tbody>
+</table>
+
+<script type='text/javascript'>
+ function each(elems, func) {
+ if (!elems instanceof Array) { elems = [elems]; }
+ for (var i = elems.length; i--; ) {
+ func(elems[i]);
+ }
+ }
+
+ function setValOn(elems, val) {
+ each(elems, function(elem) {
+ elem.innerHTML = val;
+ });
+ }
+
+ function onClick(elems, func) {
+ each(elems, function(elem) {
+ elem.onclick = func;
+ });
+ }
+
+ // Enables functionality to toggle between `_path` and `_url` helper suffixes
+ function setupRouteToggleHelperLinks() {
+ var toggleLinks = document.querySelectorAll('#route_table [data-route-helper]');
+ onClick(toggleLinks, function(){
+ var helperTxt = this.getAttribute("data-route-helper");
+ var helperElems = document.querySelectorAll('[data-route-name] span.helper');
+ setValOn(helperElems, helperTxt);
+ });
+ }
+
+ setupRouteToggleHelperLinks();
+</script>
@@ -53,9 +53,11 @@ module AssetTagHelper
#
def javascript_include_tag(*sources)
options = sources.extract_options!.stringify_keys
+ path_options = options.extract!('protocol').symbolize_keys
+
sources.uniq.map { |source|
tag_options = {
- "src" => path_to_javascript(source)
+ "src" => path_to_javascript(source, path_options)
}.merge(options)
content_tag(:script, "", tag_options)
}.join("\n").html_safe
@@ -89,11 +91,13 @@ def javascript_include_tag(*sources)
#
def stylesheet_link_tag(*sources)
options = sources.extract_options!.stringify_keys
+ path_options = options.extract!('protocol').symbolize_keys
+
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
- "href" => path_to_stylesheet(source)
+ "href" => path_to_stylesheet(source, path_options)
}.merge(options)
tag(:link, tag_options)
}.join("\n").html_safe
@@ -358,6 +358,17 @@ def test_javascript_include_tag_is_html_safe
assert javascript_include_tag("prototype").html_safe?
end
+ def test_javascript_include_tag_relative_protocol
+ @controller.config.asset_host = "assets.example.com"
+ assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag('prototype', protocol: :relative)
+ end
+
+ def test_javascript_include_tag_default_protocol
+ @controller.config.asset_host = "assets.example.com"
+ @controller.config.default_asset_host_protocol = :relative
+ assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag('prototype')
+ end
+
def test_stylesheet_path
StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -398,7 +409,18 @@ def test_stylesheet_link_tag_escapes_options
end
def test_stylesheet_link_tag_should_not_output_the_same_asset_twice
- assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', 'wellington', 'amsterdam')
+ assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', 'wellington', 'amsterdam')
+ end
+
+ def test_stylesheet_link_tag_with_relative_protocol
+ @controller.config.asset_host = "assets.example.com"
+ assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', protocol: :relative)
+ end
+
+ def test_stylesheet_link_tag_with_default_protocol
+ @controller.config.asset_host = "assets.example.com"
+ @controller.config.default_asset_host_protocol = :relative
+ assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington')
end
def test_image_path
@@ -1,5 +1,14 @@
## Rails 4.0.0 (unreleased) ##
+* Added support for `validates_uniqueness_of` in PostgreSQL array columns.
+ Fixes #8075.
+
+ *Pedro Padron*
+
+* Allow int4range and int8range columns to be created in PostgreSQL and properly convert to/from database.
+
+ *Alexey Vasiliev aka leopard*
+
* Do not log the binding values for binary columns.
*Matthew M. Boedicker*
@@ -126,6 +126,7 @@ def type_cast_code(var_name)
when :hstore then "#{klass}.string_to_hstore(#{var_name})"
when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})"
when :json then "#{klass}.string_to_json(#{var_name})"
+ when :intrange then "#{klass}.string_to_intrange(#{var_name})"
else var_name
end
end
@@ -92,6 +92,36 @@ def string_to_array(string, oid)
parse_pg_array(string).map{|val| oid.type_cast val}
end
+ def string_to_intrange(string)
+ if string.nil?
+ nil
+ elsif "empty" == string
+ (nil..nil)
+ elsif String === string && (matches = /^(\(|\[)([0-9]+),(\s?)([0-9]+)(\)|\])$/i.match(string))
+ lower_bound = ("(" == matches[1] ? (matches[2].to_i + 1) : matches[2].to_i)
+ upper_bound = (")" == matches[5] ? (matches[4].to_i - 1) : matches[4].to_i)
+ (lower_bound..upper_bound)
+ else
+ string
+ end
+ end
+
+ def intrange_to_string(object)
+ if object.nil?
+ nil
+ elsif Range === object
+ if [object.first, object.last].all? { |el| Integer === el }
+ "[#{object.first.to_i},#{object.exclude_end? ? object.last.to_i : object.last.to_i + 1})"
+ elsif [object.first, object.last].all? { |el| NilClass === el }
+ "empty"
+ else
+ nil
+ end
+ else
+ object
+ end
+ end
+
private
HstorePair = begin
@@ -168,6 +168,14 @@ def type_cast(value)
end
end
+ class IntRange < Type
+ def type_cast(value)
+ return if value.nil?
+
+ ConnectionAdapters::PostgreSQLColumn.string_to_intrange value
+ end
+ end
+
class TypeMap
def initialize
@mapping = {}
@@ -269,6 +277,9 @@ def self.registered_type?(name)
register_type 'hstore', OID::Hstore.new
register_type 'json', OID::Json.new
+ register_type 'int4range', OID::IntRange.new
+ alias_type 'int8range', 'int4range'
+
register_type 'cidr', OID::Cidr.new
alias_type 'inet', 'cidr'
end
@@ -31,6 +31,11 @@ def quote(value, column = nil) #:nodoc:
when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
else super
end
+ when Range
+ case column.sql_type
+ when 'int4range', 'int8range' then super(PostgreSQLColumn.intrange_to_string(value), column)
+ else super
+ end
when IPAddr
case column.sql_type
when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
@@ -89,6 +94,11 @@ def type_cast(value, column, array_member = false)
when 'json' then PostgreSQLColumn.json_to_string(value)
else super(value, column)
end
+ when Range
+ case column.sql_type
+ when 'int4range', 'int8range' then PostgreSQLColumn.intrange_to_string(value)
+ else super(value, column)
+ end
when IPAddr
return super(value, column) unless ['inet','cidr'].include? column.sql_type
PostgreSQLColumn.cidr_to_string(value)
@@ -417,6 +417,14 @@ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
when 0..6; "timestamp(#{precision})"
else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
end
+ when 'intrange'
+ return 'int4range' unless limit
+
+ case limit
+ when 1..4; 'int4range'
+ when 5..8; 'int8range'
+ else raise(ActiveRecordError, "No range type has byte size #{limit}. Use a numeric with precision 0 instead.")
+ end
else
super
end
@@ -114,6 +114,9 @@ def self.extract_value_from_default(default)
# JSON
when /\A'(.*)'::json\z/
$1
+ # int4range, int8range
+ when /\A'(.*)'::int(4|8)range\z/
+ $1
# Object identifier types
when /\A-?\d+\z/
$1
@@ -209,9 +212,12 @@ def simplified_type(field_type)
# UUID type
when 'uuid'
:uuid
- # JSON type
- when 'json'
- :json
+ # JSON type
+ when 'json'
+ :json
+ # int4range, int8range types
+ when 'int4range', 'int8range'
+ :intrange
# Small and big integer types
when /^(?:small|big)int$/
:integer
@@ -289,6 +295,10 @@ def json(name, options = {})
column(name, 'json', options)
end
+ def intrange(name, options = {})
+ column(name, 'intrange', options)
+ end
+
def column(name, type = nil, options = {})
super
column = self[name]
@@ -329,7 +339,8 @@ def new_column_definition(base, name, type)
cidr: { name: "cidr" },
macaddr: { name: "macaddr" },
uuid: { name: "uuid" },
- json: { name: "json" }
+ json: { name: "json" },
+ intrange: { name: "int4range" }
}
include Quoting
Oops, something went wrong.

0 comments on commit 09aeee7

Please sign in to comment.