aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test/cases/attribute_assignment_test.rb
blob: 448f8587fd3c23651f2da793eb6dcb3595098bdc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# frozen_string_literal: true

require "cases/helper"
require "active_support/core_ext/hash/indifferent_access"
require "active_support/hash_with_indifferent_access"

class AttributeAssignmentTest < ActiveModel::TestCase
  class Model
    include ActiveModel::AttributeAssignment

    attr_accessor :name, :description

    def initialize(attributes = {})
      assign_attributes(attributes)
    end

    def broken_attribute=(value)
      raise ErrorFromAttributeWriter
    end

    private
      attr_writer :metadata
  end

  class ErrorFromAttributeWriter < StandardError
  end

  class ProtectedParams
    attr_accessor :permitted
    alias :permitted? :permitted

    delegate :keys, :key?, :has_key?, :empty?, to: :@parameters

    def initialize(attributes)
      @parameters = attributes.with_indifferent_access
      @permitted = false
    end

    def permit!
      @permitted = true
      self
    end

    def [](key)
      @parameters[key]
    end

    def to_h
      @parameters
    end

    def stringify_keys
      dup
    end

    def dup
      super.tap do |duplicate|
        duplicate.instance_variable_set :@permitted, permitted?
      end
    end
  end

  test "simple assignment" do
    model = Model.new

    model.assign_attributes(name: "hello", description: "world")
    assert_equal "hello", model.name
    assert_equal "world", model.description
  end

  test "assign non-existing attribute" do
    model = Model.new
    error = assert_raises(ActiveModel::UnknownAttributeError) do
      model.assign_attributes(hz: 1)
    end

    assert_equal model, error.record
    assert_equal "hz", error.attribute
  end

  test "assign private attribute" do
    model = Model.new
    assert_raises(ActiveModel::UnknownAttributeError) do
      model.assign_attributes(metadata: { a: 1 })
    end
  end

  test "does not swallow errors raised in an attribute writer" do
    assert_raises(ErrorFromAttributeWriter) do
      Model.new(broken_attribute: 1)
    end
  end

  test "an ArgumentError is raised if a non-hash-like object is passed" do
    assert_raises(ArgumentError) do
      Model.new(1)
    end
  end

  test "forbidden attributes cannot be used for mass assignment" do
    params = ProtectedParams.new(name: "Guille", description: "m")

    assert_raises(ActiveModel::ForbiddenAttributesError) do
      Model.new(params)
    end
  end

  test "permitted attributes can be used for mass assignment" do
    params = ProtectedParams.new(name: "Guille", description: "desc")
    params.permit!
    model = Model.new(params)

    assert_equal "Guille", model.name
    assert_equal "desc", model.description
  end

  test "regular hash should still be used for mass assignment" do
    model = Model.new(name: "Guille", description: "m")

    assert_equal "Guille", model.name
    assert_equal "m", model.description
  end

  test "assigning no attributes should not raise, even if the hash is un-permitted" do
    model = Model.new
    assert_nil model.assign_attributes(ProtectedParams.new({}))
  end
end