aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb2
-rw-r--r--activemodel/CHANGELOG.md4
-rw-r--r--activemodel/lib/active_model/secure_password.rb2
-rw-r--r--activemodel/test/cases/secure_password_test.rb8
-rw-r--r--activerecord/CHANGELOG.md6
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb77
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb25
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb4
-rw-r--r--activerecord/lib/active_record/relation/merger.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb6
-rw-r--r--activerecord/test/cases/relations_test.rb8
-rw-r--r--guides/source/action_view_overview.md2
-rw-r--r--guides/source/active_record_basics.md2
-rw-r--r--guides/source/active_record_validations.md2
-rw-r--r--guides/source/getting_started.md4
-rw-r--r--railties/lib/rails/cli.rb1
17 files changed, 77 insertions, 80 deletions
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 8a4918a8c0..2f5246f42a 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -455,7 +455,7 @@ module ActionView
html_options, name = name, nil if block_given?
html_options = (html_options || {}).stringify_keys
- extras = %w{ cc bcc body subject }.map { |item|
+ extras = %w{ cc bcc body subject }.map! { |item|
option = html_options.delete(item) || next
"#{item}=#{Rack::Utils.escape_path(option)}"
}.compact
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index eb21b69163..e8602ecbcf 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Fix `has_secure_password` to honor bcrypt-ruby's cost attribute.
+
+ *T.J. Schuck*
+
* Updated the `ActiveModel::Dirty#changed_attributes` method to be indifferent between using
symbols and strings as keys.
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 17fafe4be9..f87c36e39e 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -103,7 +103,7 @@ module ActiveModel
def password=(unencrypted_password)
unless unencrypted_password.blank?
@password = unencrypted_password
- cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST
+ cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
end
end
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index 98e5c747d5..41d0b2263e 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -82,6 +82,14 @@ class SecurePasswordTest < ActiveModel::TestCase
assert_equal BCrypt::Engine::DEFAULT_COST, @user.password_digest.cost
end
+ test "Password digest cost honors bcrypt cost attribute when min_cost is false" do
+ ActiveModel::SecurePassword.min_cost = false
+ BCrypt::Engine.cost = 5
+
+ @user.password = "secret"
+ assert_equal BCrypt::Engine.cost, @user.password_digest.cost
+ end
+
test "Password digest cost can be set to bcrypt min cost to speed up tests" do
ActiveModel::SecurePassword.min_cost = true
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 83c94caa53..c3c4ae7862 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -199,6 +199,12 @@
*Yves Senn*
+* Fixes bug when using includes combined with select, the select statement was overwritten.
+
+ Fixes #11773
+
+ *Edo Balvers*
+
* Load fixtures from linked folders.
*Kassio Borges*
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index e2d4cf4378..6e08f67286 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -61,32 +61,26 @@ module ActiveRecord
build tree, @join_root, Arel::InnerJoin
end
- def graft(*associations)
- associations.reject { |join_node|
- find_node join_node
- }.each { |join_node|
- parent = find_node(join_node.parent) || join_root
- reflection = join_node.reflection
- type = join_node.join_type
-
- next if parent.children.find { |j| j.reflection == reflection }
- build_scalar reflection, parent, type
- }
- self
- end
-
def reflections
join_root.drop(1).map!(&:reflection)
end
- def join_relation(relation)
- nodes = join_root.drop 1
- nodes.each { |n| n.join_type = Arel::OuterJoin }
- relation.joins(nodes)
+ def merge_outer_joins!(other)
+ left = join_root
+ right = other.join_root
+
+ if left.match? right
+ merge_node left, right
+ else
+ # If the roots aren't the same, then deep copy the RHS to the LHS
+ left.children.concat right.children.map { |node|
+ deep_copy left, node
+ }
+ end
end
def join_constraints
- join_root.flat_map(&:join_constraints)
+ join_root.children.flat_map { |c| c.flat_map(&:join_constraints) }
end
def columns
@@ -103,39 +97,34 @@ module ActiveRecord
parents = {}
type_caster = result_set.column_type primary_key
- assoc = join_root.children
records = result_set.map { |row_hash|
primary_id = type_caster.type_cast row_hash[primary_key]
parent = parents[primary_id] ||= join_root.instantiate(row_hash)
- construct(parent, assoc, row_hash, result_set)
+ construct(parent, join_root, row_hash, result_set)
parent
}.uniq
- remove_duplicate_results!(base_klass, records, assoc)
+ remove_duplicate_results!(base_klass, records, join_root.children)
records
end
private
- def find_node(target_node)
- stack = target_node.parents << target_node
-
- left = [join_root]
- right = stack.shift
+ def merge_node(left, right)
+ intersection, missing = right.children.map { |node1|
+ [left.children.find { |node2| node1.match? node2 }, node1]
+ }.partition(&:first)
- loop {
- match = left.find { |l| l.match? right }
+ intersection.each { |l,r| merge_node l, r }
- if match
- return match if stack.empty?
+ left.children.concat missing.map { |_,node| deep_copy left, node }
+ end
- left = match.children
- right = stack.shift
- else
- return nil
- end
- }
+ def deep_copy(parent, node)
+ dup = build_join_association(node.reflection, parent, Arel::OuterJoin)
+ dup.children.concat node.children.map { |n| deep_copy dup, n }
+ dup
end
def remove_duplicate_results!(base, records, associations)
@@ -195,16 +184,16 @@ module ActiveRecord
JoinAssociation.new(reflection, join_root.to_a.length, parent, join_type, alias_tracker)
end
- def construct(parent, nodes, row, rs)
- nodes.sort_by { |k| k.name }.each do |node|
- association = construct_association(parent, node, row, rs)
- construct(association, node.children, row, rs) if association
+ def construct(ar_parent, parent, row, rs)
+ parent.children.each do |node|
+ association = construct_association(ar_parent, parent, node, row, rs)
+ construct(association, node, row, rs) if association
end
end
- def construct_association(record, join_part, row, rs)
- caster = rs.column_type(join_part.parent.aliased_primary_key)
- row_id = caster.type_cast row[join_part.parent.aliased_primary_key]
+ def construct_association(record, parent, join_part, row, rs)
+ caster = rs.column_type(parent.aliased_primary_key)
+ row_id = caster.type_cast row[parent.aliased_primary_key]
return if record.id != row_id
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index d536eaf613..d39ce94c99 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -29,9 +29,6 @@ module ActiveRecord
@children = []
end
- def join_constraints; []; end
- def join_relation(rel); rel; end
-
def name
reflection.name
end
@@ -40,25 +37,9 @@ module ActiveRecord
self.class == other.class
end
- def parents
- parents = []
- node = parent
- while node
- parents.unshift node
- node = node.parent
- end
- parents
- end
-
- def each
+ def each(&block)
yield self
- iter = lambda { |list|
- list.each { |item|
- yield item
- iter.call item.children
- }
- }
- iter.call children
+ children.each { |child| child.each(&block) }
end
def aliased_table
@@ -90,7 +71,7 @@ module ActiveRecord
unless @column_names_with_alias
@column_names_with_alias = []
- ([primary_key] + (column_names - [primary_key])).compact.each_with_index do |column_name, i|
+ column_names.each_with_index do |column_name, i|
@column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index ea21836c65..3166df57eb 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -15,7 +15,7 @@ module ActiveRecord
through_reflection.name,
through_scope)
- through_records = owners.map do |owner, h|
+ through_records = owners.map do |owner|
association = owner.association through_reflection.name
[owner, Array(association.reader)]
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 0132a02f83..8583286de5 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -261,13 +261,13 @@ module ActiveRecord
end
def construct_relation_for_association_find(join_dependency)
- relation = except(:select).select(join_dependency.columns)
+ relation = except(:select).select(join_dependency.columns + select_values)
apply_join_dependency(relation, join_dependency)
end
def apply_join_dependency(relation, join_dependency)
relation = relation.except(:includes, :eager_load, :preload)
- relation = join_dependency.join_relation(relation)
+ relation = relation.joins join_dependency
if using_limitable_reflections?(join_dependency.reflections)
relation
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index c05632e688..182b9ed89c 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -94,7 +94,7 @@ module ActiveRecord
[])
relation.joins! rest
- @relation = join_dependency.join_relation(relation)
+ @relation = relation.joins join_dependency
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index e1efc6a189..9c9690215a 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -928,7 +928,7 @@ module ActiveRecord
:string_join
when Hash, Symbol, Array
:association_join
- when ActiveRecord::Associations::JoinDependency::JoinAssociation
+ when ActiveRecord::Associations::JoinDependency
:stashed_join
when Arel::Nodes::Join
:join_node
@@ -950,7 +950,9 @@ module ActiveRecord
join_list
)
- join_dependency.graft(*stashed_association_joins)
+ stashed_association_joins.each do |dep|
+ join_dependency.merge_outer_joins! dep
+ end
joins = join_dependency.join_constraints
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index f814947ab2..396d4ef1e9 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -486,6 +486,14 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Developer.where(name: 'David').map(&:id).sort, developers
end
+ def test_includes_with_select
+ query = Post.select('comments_count AS ranking').order('ranking').includes(:comments)
+ .where(comments: { id: 1 })
+
+ assert_equal ['comments_count AS ranking'], query.select_values
+ assert_equal 1, query.to_a.size
+ end
+
def test_loading_with_one_association
posts = Post.preload(:comments)
post = posts.find { |p| p.id == 1 }
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index 94aa0f8502..d19dd11181 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -269,7 +269,7 @@ Rails will render the `_product_ruler` partial (with no data passed to it) betwe
### Layouts
-Layouts can be used to render a common view template around the results of Rails controller actions. Typically, every Rails has a couple of overall layouts that most pages are rendered within. For example, a site might have a layout for a logged in user, and a layout for the marketing or sales side of the site. The logged in user layout might include top-level navigation that should be present across many controller actions. The sales layout for a SaaS app might include top-level navigation for things like "Pricing" and "Contact Us." You would expect each layout to have a different look and feel. You can read more details about Layouts in the [Layouts and Rendering in Rails](layouts_and_rendering.html) guide.
+Layouts can be used to render a common view template around the results of Rails controller actions. Typically, every Rails application has a couple of overall layouts that most pages are rendered within. For example, a site might have a layout for a logged in user, and a layout for the marketing or sales side of the site. The logged in user layout might include top-level navigation that should be present across many controller actions. The sales layout for a SaaS app might include top-level navigation for things like "Pricing" and "Contact Us." You would expect each layout to have a different look and feel. You can read more details about Layouts in the [Layouts and Rendering in Rails](layouts_and_rendering.html) guide.
Partial Layouts
---------------
diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md
index 34baae509b..a184f0753d 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -116,7 +116,7 @@ to Active Record instances:
locking](http://api.rubyonrails.org/classes/ActiveRecord/Locking.html) to
a model.
* `type` - Specifies that the model uses [Single Table
- Inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html).
+ Inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance).
* `(association_name)_type` - Stores the type for
[polymorphic associations](association_basics.html#polymorphic-associations).
* `(table_name)_count` - Used to cache the number of belonging objects on
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 339612ebc5..797b996357 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -528,7 +528,7 @@ If you validate the presence of an object associated via a `has_one` or
Since `false.blank?` is true, if you want to validate the presence of a boolean
field you should use `validates :field_name, inclusion: { in: [true, false] }`.
-The default error message is _"can't be empty"_.
+The default error message is _"can't be blank"_.
### `absence`
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index bb2e8e906f..2f322d15da 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -1490,8 +1490,8 @@ So first, we'll wire up the Post show template
</p>
<% end %>
-<%= link_to 'Edit Post', edit_post_path(@post) %> |
-<%= link_to 'Back to Posts', posts_path %>
+<%= link_to 'Back', posts_path %>
+| <%= link_to 'Edit', edit_post_path(@post) %>
```
This adds a form on the `Post` show page that creates a new comment by
diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb
index 20313a2608..dd70c272c6 100644
--- a/railties/lib/rails/cli.rb
+++ b/railties/lib/rails/cli.rb
@@ -1,4 +1,3 @@
-require 'rbconfig'
require 'rails/app_rails_loader'
# If we are inside a Rails application this method performs an exec and thus