README.rdoc 6.4 KB
Newer Older
M
Mislav Marohnić 已提交
1 2 3
= Active Model -- model interfaces for Rails

Active Model provides a known set of interfaces for usage in model classes.
4
They allow for Action Pack helpers to interact with non-Active Record models,
W
Waynn Lue 已提交
5
for example. Active Model also helps with building custom ORMs for use outside of
M
Mislav Marohnić 已提交
6 7 8 9 10
the Rails framework.

Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
interact with Action Pack helpers, it was required to either copy chunks of
code from Rails, or monkey patch entire helpers to make them handle objects
R
R.T. Lechow 已提交
11
that did not exactly conform to the Active Record interface. This would result
J
José Valim 已提交
12 13
in code duplication and fragile applications that broke on upgrades. Active
Model solves this by defining an explicit API. You can read more about the
14
API in <tt>ActiveModel::Lint::Tests</tt>.
M
Mislav Marohnić 已提交
15

16
Active Model provides a default module that implements the basic API required
17
to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>.
18 19 20 21 22 23 24 25

    class Person
      include ActiveModel::Model

      attr_accessor :name, :age
      validates_presence_of :name
    end

26
    person = Person.new(name: 'bob', age: '18')
27 28
    person.name   # => 'bob'
    person.age    # => '18'
29
    person.valid? # => true
30

31 32
It includes model name introspections, conversions, translations and
validations, resulting in a class suitable to be used with Action Pack.
V
Vijay Dev 已提交
33
See <tt>ActiveModel::Model</tt> for more examples.
34

J
José Valim 已提交
35 36
Active Model also provides the following functionality to have ORM-like
behavior out of the box:
M
Mislav Marohnić 已提交
37 38 39

* Add attribute magic to objects

40 41
    class Person
      include ActiveModel::AttributeMethods
42

43
      attribute_method_prefix 'clear_'
44
      define_attribute_methods :name, :age
45

46
      attr_accessor :name, :age
47

48 49 50 51
      def clear_attribute(attr)
        send("#{attr}=", nil)
      end
    end
52

53
    person = Person.new
M
Mislav Marohnić 已提交
54 55
    person.clear_name
    person.clear_age
56

57
  {Learn more}[link:classes/ActiveModel/AttributeMethods.html]
58

M
Mislav Marohnić 已提交
59
* Callbacks for certain operations
M
Mikel Lindsaar 已提交
60

61
    class Person
M
Mikel Lindsaar 已提交
62 63
      extend ActiveModel::Callbacks
      define_model_callbacks :create
64

M
Mikel Lindsaar 已提交
65
      def create
66
        run_callbacks :create do
M
Mikel Lindsaar 已提交
67 68 69 70
          # Your create action methods here
        end
      end
    end
71

M
Mislav Marohnić 已提交
72 73
  This generates +before_create+, +around_create+ and +after_create+
  class methods that wrap your create method.
74

75
  {Learn more}[link:classes/ActiveModel/Callbacks.html]
76

M
Mislav Marohnić 已提交
77
* Tracking value changes
78

79 80 81
    class Person
      include ActiveModel::Dirty

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
      define_attribute_methods :name

      def name
        @name
      end

      def name=(val)
        name_will_change! unless val == @name
        @name = val
      end

      def save
        # do persistence work
        changes_applied
      end
97
    end
M
Mikel Lindsaar 已提交
98

99
    person = Person.new
100 101
    person.name             # => nil
    person.changed?         # => false
M
Mikel Lindsaar 已提交
102
    person.name = 'bob'
103 104 105
    person.changed?         # => true
    person.changed          # => ['name']
    person.changes          # => { 'name' => [nil, 'bob'] }
106
    person.save
M
Mikel Lindsaar 已提交
107 108 109
    person.name = 'robert'
    person.save
    person.previous_changes # => {'name' => ['bob, 'robert']}
110

111
  {Learn more}[link:classes/ActiveModel/Dirty.html]
112

M
Mislav Marohnić 已提交
113
* Adding +errors+ interface to objects
114

M
Mislav Marohnić 已提交
115 116
  Exposing error messages allows objects to interact with Action Pack
  helpers seamlessly.
117

118
    class Person
119

120 121 122
      def initialize
        @errors = ActiveModel::Errors.new(self)
      end
123

124 125
      attr_accessor :name
      attr_reader   :errors
126

127
      def validate!
128
        errors.add(:name, "cannot be nil") if name.nil?
129
      end
130

C
Carlos Antonio da Silva 已提交
131
      def self.human_attribute_name(attr, options = {})
132 133 134
        "Name"
      end
    end
135

136 137 138
    person = Person.new
    person.name = nil
    person.validate!
139
    person.errors.full_messages
140
    # => ["Name cannot be nil"]
141

142
  {Learn more}[link:classes/ActiveModel/Errors.html]
143

M
Mislav Marohnić 已提交
144
* Model name introspection
145

146 147 148
    class NamedPerson
      extend ActiveModel::Naming
    end
149

150
    NamedPerson.model_name.name   # => "NamedPerson"
P
Paco Guzman 已提交
151
    NamedPerson.model_name.human  # => "Named person"
152

153
  {Learn more}[link:classes/ActiveModel/Naming.html]
154

M
Mislav Marohnić 已提交
155
* Making objects serializable
156

J
Julio Lopez 已提交
157
  <tt>ActiveModel::Serialization</tt> provides a standard interface for your object
158
  to provide +to_json+ serialization.
159

160 161 162 163 164 165 166 167 168 169
    class SerialPerson
      include ActiveModel::Serialization

      attr_accessor :name

      def attributes
        {'name' => name}
      end
    end

170 171
    s = SerialPerson.new
    s.serializable_hash   # => {"name"=>nil}
172 173 174 175 176 177

    class SerialPerson
      include ActiveModel::Serializers::JSON
    end

    s = SerialPerson.new
178
    s.to_json             # => "{\"name\":null}"
179

180
  {Learn more}[link:classes/ActiveModel/Serialization.html]
M
Mikel Lindsaar 已提交
181

M
Mislav Marohnić 已提交
182
* Internationalization (i18n) support
183 184 185 186

    class Person
      extend ActiveModel::Translation
    end
187

M
Mislav Marohnić 已提交
188
    Person.human_attribute_name('my_attribute')
P
Paco Guzman 已提交
189
    # => "My attribute"
190

191
  {Learn more}[link:classes/ActiveModel/Translation.html]
192

M
Mislav Marohnić 已提交
193
* Validation support
194

195 196
    class Person
      include ActiveModel::Validations
197

198
      attr_accessor :first_name, :last_name
199

200 201 202 203
      validates_each :first_name, :last_name do |record, attr, value|
        record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
      end
    end
204

205 206 207
    person = Person.new
    person.first_name = 'zoolander'
    person.valid?  # => false
208

209
  {Learn more}[link:classes/ActiveModel/Validations.html]
210

M
Mislav Marohnić 已提交
211
* Custom validators
212

213 214
    class HasNameValidator < ActiveModel::Validator
      def validate(record)
215
        record.errors.add(:name, "must exist") if record.name.blank?
216 217 218 219 220 221 222 223
      end
    end

    class ValidatorPerson
      include ActiveModel::Validations
      validates_with HasNameValidator
      attr_accessor :name
    end
224

225 226 227 228 229
    p = ValidatorPerson.new
    p.valid?                  # =>  false
    p.errors.full_messages    # => ["Name must exist"]
    p.name = "Bob"
    p.valid?                  # =>  true
230

231
  {Learn more}[link:classes/ActiveModel/Validator.html]
J
José Valim 已提交
232

233 234 235

== Download and installation

W
Waynn Lue 已提交
236
The latest version of Active Model can be installed with RubyGems:
237

238
  $ gem install activemodel
239 240 241

Source code can be downloaded as part of the Rails project on GitHub

242
* https://github.com/rails/rails/tree/master/activemodel
243 244 245 246


== License

247 248
Active Model is released under the MIT license:

249
* https://opensource.org/licenses/MIT
250 251 252 253


== Support

F
Fatos Morina 已提交
254
API documentation is at:
255

256
* https://api.rubyonrails.org
257

F
Fatos Morina 已提交
258
Bug reports for the Ruby on Rails project can be filed here:
259 260

* https://github.com/rails/rails/issues
261 262 263 264

Feature requests should be discussed on the rails-core mailing list here:

* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core