diff options
6 files changed, 58 insertions, 10 deletions
diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb index a7b4706906..3f9feb7631 100644 --- a/activemodel/lib/active_model/mass_assignment_security.rb +++ b/activemodel/lib/active_model/mass_assignment_security.rb @@ -1,5 +1,6 @@  require 'active_support/core_ext/class/attribute'  require 'active_support/core_ext/string/inflections' +require 'active_support/core_ext/array/wrap'  require 'active_model/mass_assignment_security/permission_set'  require 'active_model/mass_assignment_security/sanitizer' @@ -110,8 +111,11 @@ module ActiveModel          options = args.extract_options!          role = options[:as] || :default -        self._protected_attributes        = protected_attributes_configs.dup -        self._protected_attributes[role] = self.protected_attributes(role) + args +        self._protected_attributes = protected_attributes_configs.dup + +        Array.wrap(role).each do |name| +          self._protected_attributes[name] = self.protected_attributes(name) + args +        end          self._active_authorizer = self._protected_attributes        end @@ -169,8 +173,11 @@ module ActiveModel          options = args.extract_options!          role = options[:as] || :default -        self._accessible_attributes       = accessible_attributes_configs.dup -        self._accessible_attributes[role] = self.accessible_attributes(role) + args +        self._accessible_attributes = accessible_attributes_configs.dup + +        Array.wrap(role).each do |name| +          self._accessible_attributes[name] = self.accessible_attributes(name) + args +        end          self._active_authorizer = self._accessible_attributes        end diff --git a/activemodel/test/cases/mass_assignment_security_test.rb b/activemodel/test/cases/mass_assignment_security_test.rb index a778240827..be07e59a2f 100644 --- a/activemodel/test/cases/mass_assignment_security_test.rb +++ b/activemodel/test/cases/mass_assignment_security_test.rb @@ -43,6 +43,20 @@ class MassAssignmentSecurityTest < ActiveModel::TestCase      assert_equal expected, sanitized    end +  def test_attributes_accessible_with_roles_given_as_array +    user = Account.new +    expected = { "name" => "John Smith", "email" => "john@smith.com" } +    sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true)) +    assert_equal expected, sanitized +  end + +  def test_attributes_accessible_with_admin_role_when_roles_given_as_array +    user = Account.new +    expected = { "name" => "John Smith", "email" => "john@smith.com", "admin" => true } +    sanitized = user.sanitize_for_mass_assignment(expected.merge("super_powers" => true), :admin) +    assert_equal expected, sanitized +  end +    def test_attributes_protected_by_default      firm = Firm.new      expected = { } diff --git a/activemodel/test/models/mass_assignment_specific.rb b/activemodel/test/models/mass_assignment_specific.rb index 53b37369ff..1d123fa58c 100644 --- a/activemodel/test/models/mass_assignment_specific.rb +++ b/activemodel/test/models/mass_assignment_specific.rb @@ -20,6 +20,14 @@ class Person    public :sanitize_for_mass_assignment  end +class Account +  include ActiveModel::MassAssignmentSecurity +  attr_accessible :name, :email, :as => [:default, :admin] +  attr_accessible :admin, :as => :admin + +  public :sanitize_for_mass_assignment +end +  class Firm    include ActiveModel::MassAssignmentSecurity @@ -65,4 +73,4 @@ end  class TightDescendant < TightPerson    attr_accessible :phone_number    attr_accessible :super_powers, :as => :admin -end
\ No newline at end of file +end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index aabe5c269b..9c5f603c01 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -146,10 +146,16 @@ module ActiveRecord        if options.except(:distinct).present?          apply_finder_options(options.except(:distinct)).calculate(operation, column_name, :distinct => options[:distinct])        else -        if eager_loading? || (includes_values.present? && references_eager_loaded_tables?) -          construct_relation_for_association_calculations.calculate(operation, column_name, options) +        relation = with_default_scope + +        if relation.equal?(self) +          if eager_loading? || (includes_values.present? && references_eager_loaded_tables?) +            construct_relation_for_association_calculations.calculate(operation, column_name, options) +          else +            perform_calculation(operation, column_name, options) +          end          else -          perform_calculation(operation, column_name, options) +          relation.calculate(operation, column_name, options)          end        end      rescue ThrowResult @@ -196,7 +202,7 @@ module ActiveRecord      def execute_simple_calculation(operation, column_name, distinct) #:nodoc:        # Postgresql doesn't like ORDER BY when there are no GROUP BY -      relation = with_default_scope.reorder(nil) +      relation = reorder(nil)        if operation == "count" && (relation.limit_value || relation.offset_value)          # Shortcut when limit is zero. @@ -245,7 +251,7 @@ module ActiveRecord          "#{field} AS #{aliaz}"        } -      relation = with_default_scope.except(:group).group(group.join(',')) +      relation = except(:group).group(group.join(','))        relation.select_values = select_values        calculated_data = @klass.connection.select_all(relation.to_sql) diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index a6e08f95d0..0e158df6a0 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -498,4 +498,11 @@ class DefaultScopingTest < ActiveRecord::TestCase      lowest_salary_dev = DeveloperOrderedBySalary.find(developers(:poor_jamis).id)      assert_equal lowest_salary_dev, DeveloperOrderedBySalary.last    end + +  def test_default_scope_include_with_count +    d = DeveloperWithIncludes.create! +    d.audit_logs.create! :message => 'foo' + +    assert_equal 1, DeveloperWithIncludes.where(:audit_logs => { :message => 'foo' }).count +  end  end diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index 98d6aa22f7..f182a7fa97 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -91,6 +91,12 @@ class DeveloperWithSelect < ActiveRecord::Base    default_scope select('name')  end +class DeveloperWithIncludes < ActiveRecord::Base +  self.table_name = 'developers' +  has_many :audit_logs, :foreign_key => :developer_id +  default_scope includes(:audit_logs) +end +  class DeveloperOrderedBySalary < ActiveRecord::Base    self.table_name = 'developers'    default_scope :order => 'salary DESC'  | 
