activemodel 3.2.22.5 → 4.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -64
- data/MIT-LICENSE +1 -1
- data/README.rdoc +61 -24
- data/lib/active_model.rb +21 -11
- data/lib/active_model/attribute_methods.rb +150 -125
- data/lib/active_model/callbacks.rb +49 -34
- data/lib/active_model/conversion.rb +39 -19
- data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
- data/lib/active_model/dirty.rb +48 -32
- data/lib/active_model/errors.rb +176 -88
- data/lib/active_model/forbidden_attributes_protection.rb +27 -0
- data/lib/active_model/lint.rb +42 -55
- data/lib/active_model/locale/en.yml +3 -1
- data/lib/active_model/model.rb +97 -0
- data/lib/active_model/naming.rb +191 -51
- data/lib/active_model/railtie.rb +11 -1
- data/lib/active_model/secure_password.rb +55 -25
- data/lib/active_model/serialization.rb +51 -27
- data/lib/active_model/serializers/json.rb +83 -46
- data/lib/active_model/serializers/xml.rb +46 -12
- data/lib/active_model/test_case.rb +0 -12
- data/lib/active_model/translation.rb +9 -10
- data/lib/active_model/validations.rb +154 -52
- data/lib/active_model/validations/absence.rb +31 -0
- data/lib/active_model/validations/acceptance.rb +10 -22
- data/lib/active_model/validations/callbacks.rb +78 -25
- data/lib/active_model/validations/clusivity.rb +41 -0
- data/lib/active_model/validations/confirmation.rb +13 -23
- data/lib/active_model/validations/exclusion.rb +26 -55
- data/lib/active_model/validations/format.rb +44 -34
- data/lib/active_model/validations/inclusion.rb +22 -52
- data/lib/active_model/validations/length.rb +48 -49
- data/lib/active_model/validations/numericality.rb +30 -32
- data/lib/active_model/validations/presence.rb +12 -22
- data/lib/active_model/validations/validates.rb +68 -36
- data/lib/active_model/validations/with.rb +28 -23
- data/lib/active_model/validator.rb +22 -22
- data/lib/active_model/version.rb +4 -4
- metadata +23 -24
- data/lib/active_model/mass_assignment_security.rb +0 -237
- data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
- data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
- data/lib/active_model/observer_array.rb +0 -147
- data/lib/active_model/observing.rb +0 -252
data/lib/active_model/lint.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
module Lint
|
3
|
-
# == Active Model Lint Tests
|
3
|
+
# == Active \Model \Lint \Tests
|
4
4
|
#
|
5
|
-
# You can test whether an object is compliant with the Active Model API by
|
6
|
-
# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
|
7
|
-
# tests that tell you whether your object is fully compliant,
|
8
|
-
# which aspects of the API are not implemented.
|
5
|
+
# You can test whether an object is compliant with the Active \Model API by
|
6
|
+
# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
|
7
|
+
# include tests that tell you whether your object is fully compliant,
|
8
|
+
# or if not, which aspects of the API are not implemented.
|
9
|
+
#
|
10
|
+
# Note an object is not required to implement all APIs in order to work
|
11
|
+
# with Action Pack. This module only intends to provide guidance in case
|
12
|
+
# you want all features out of the box.
|
9
13
|
#
|
10
14
|
# These tests do not attempt to determine the semantic correctness of the
|
11
|
-
# returned values. For instance, you could implement valid
|
12
|
-
# return true, and the tests would pass. It is up to you to ensure
|
13
|
-
# the values are semantically meaningful.
|
15
|
+
# returned values. For instance, you could implement <tt>valid?</tt> to
|
16
|
+
# always return true, and the tests would pass. It is up to you to ensure
|
17
|
+
# that the values are semantically meaningful.
|
14
18
|
#
|
15
|
-
# Objects you pass in are expected to return a compliant object from a
|
16
|
-
#
|
19
|
+
# Objects you pass in are expected to return a compliant object from a call
|
20
|
+
# to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
|
21
|
+
# +self+.
|
17
22
|
module Tests
|
18
23
|
|
19
24
|
# == Responds to <tt>to_key</tt>
|
20
25
|
#
|
21
26
|
# Returns an Enumerable of all (primary) key attributes
|
22
|
-
# or nil if model.persisted
|
27
|
+
# or nil if <tt>model.persisted?</tt> is false. This is used by
|
28
|
+
# <tt>dom_id</tt> to generate unique ids for the object.
|
23
29
|
def test_to_key
|
24
30
|
assert model.respond_to?(:to_key), "The model should respond to to_key"
|
25
31
|
def model.persisted?() false end
|
@@ -29,13 +35,14 @@ module ActiveModel
|
|
29
35
|
# == Responds to <tt>to_param</tt>
|
30
36
|
#
|
31
37
|
# Returns a string representing the object's key suitable for use in URLs
|
32
|
-
# or nil if model.persisted
|
38
|
+
# or +nil+ if <tt>model.persisted?</tt> is +false+.
|
33
39
|
#
|
34
|
-
# Implementers can decide to either raise an exception or provide a
|
35
|
-
# in case the record uses a composite primary key. There are no
|
36
|
-
# behavior in lint because it doesn't make sense to force
|
37
|
-
# implementation strategies on the implementer.
|
38
|
-
# not persisted?, then to_param
|
40
|
+
# Implementers can decide to either raise an exception or provide a
|
41
|
+
# default in case the record uses a composite primary key. There are no
|
42
|
+
# tests for this behavior in lint because it doesn't make sense to force
|
43
|
+
# any of the possible implementation strategies on the implementer.
|
44
|
+
# However, if the resource is not persisted?, then <tt>to_param</tt>
|
45
|
+
# should always return +nil+.
|
39
46
|
def test_to_param
|
40
47
|
assert model.respond_to?(:to_param), "The model should respond to to_param"
|
41
48
|
def model.to_key() [1] end
|
@@ -45,70 +52,50 @@ module ActiveModel
|
|
45
52
|
|
46
53
|
# == Responds to <tt>to_partial_path</tt>
|
47
54
|
#
|
48
|
-
# Returns a string giving a relative path.
|
55
|
+
# Returns a string giving a relative path. This is used for looking up
|
49
56
|
# partials. For example, a BlogPost model might return "blog_posts/blog_post"
|
50
|
-
#
|
51
57
|
def test_to_partial_path
|
52
58
|
assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path"
|
53
59
|
assert_kind_of String, model.to_partial_path
|
54
60
|
end
|
55
61
|
|
56
|
-
# == Responds to <tt>valid?</tt>
|
57
|
-
#
|
58
|
-
# Returns a boolean that specifies whether the object is in a valid or invalid
|
59
|
-
# state.
|
60
|
-
def test_valid?
|
61
|
-
assert model.respond_to?(:valid?), "The model should respond to valid?"
|
62
|
-
assert_boolean model.valid?, "valid?"
|
63
|
-
end
|
64
|
-
|
65
62
|
# == Responds to <tt>persisted?</tt>
|
66
63
|
#
|
67
|
-
# Returns a boolean that specifies whether the object has been persisted
|
68
|
-
# This is used when calculating the URL for an object. If the object
|
69
|
-
# not persisted, a form for that object, for instance, will
|
70
|
-
#
|
71
|
-
#
|
64
|
+
# Returns a boolean that specifies whether the object has been persisted
|
65
|
+
# yet. This is used when calculating the URL for an object. If the object
|
66
|
+
# is not persisted, a form for that object, for instance, will route to
|
67
|
+
# the create action. If it is persisted, a form for the object will routes
|
68
|
+
# to the update action.
|
72
69
|
def test_persisted?
|
73
70
|
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
|
74
71
|
assert_boolean model.persisted?, "persisted?"
|
75
72
|
end
|
76
73
|
|
77
|
-
# == Naming
|
74
|
+
# == \Naming
|
78
75
|
#
|
79
76
|
# Model.model_name must return a string with some convenience methods:
|
80
|
-
#
|
81
|
-
#
|
77
|
+
# <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
|
78
|
+
# ActiveModel::Naming for more information.
|
82
79
|
def test_model_naming
|
83
80
|
assert model.class.respond_to?(:model_name), "The model should respond to model_name"
|
84
81
|
model_name = model.class.model_name
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
82
|
+
assert model_name.respond_to?(:to_str)
|
83
|
+
assert model_name.human.respond_to?(:to_str)
|
84
|
+
assert model_name.singular.respond_to?(:to_str)
|
85
|
+
assert model_name.plural.respond_to?(:to_str)
|
89
86
|
end
|
90
87
|
|
91
|
-
# == Errors Testing
|
92
|
-
#
|
93
|
-
# Returns an object that has :[] and :full_messages defined on it. See below
|
94
|
-
# for more details.
|
88
|
+
# == \Errors Testing
|
95
89
|
#
|
96
|
-
# Returns an
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# return an empty Array.
|
90
|
+
# Returns an object that implements [](attribute) defined which returns an
|
91
|
+
# Array of Strings that are the errors for the attribute in question.
|
92
|
+
# If localization is used, the Strings should be localized for the current
|
93
|
+
# locale. If no error is present, this method should return an empty Array.
|
100
94
|
def test_errors_aref
|
101
95
|
assert model.respond_to?(:errors), "The model should respond to errors"
|
102
96
|
assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array"
|
103
97
|
end
|
104
98
|
|
105
|
-
# Returns an Array of all error messages for the object. Each message
|
106
|
-
# should contain information about the field, if applicable.
|
107
|
-
def test_errors_full_messages
|
108
|
-
assert model.respond_to?(:errors), "The model should respond to errors"
|
109
|
-
assert model.errors.full_messages.is_a?(Array), "errors#full_messages should return an Array"
|
110
|
-
end
|
111
|
-
|
112
99
|
private
|
113
100
|
def model
|
114
101
|
assert @model.respond_to?(:to_model), "The object should respond_to to_model"
|
@@ -9,10 +9,11 @@ en:
|
|
9
9
|
inclusion: "is not included in the list"
|
10
10
|
exclusion: "is reserved"
|
11
11
|
invalid: "is invalid"
|
12
|
-
confirmation: "doesn't match
|
12
|
+
confirmation: "doesn't match %{attribute}"
|
13
13
|
accepted: "must be accepted"
|
14
14
|
empty: "can't be empty"
|
15
15
|
blank: "can't be blank"
|
16
|
+
present: "must be blank"
|
16
17
|
too_long: "is too long (maximum is %{count} characters)"
|
17
18
|
too_short: "is too short (minimum is %{count} characters)"
|
18
19
|
wrong_length: "is the wrong length (should be %{count} characters)"
|
@@ -23,5 +24,6 @@ en:
|
|
23
24
|
equal_to: "must be equal to %{count}"
|
24
25
|
less_than: "must be less than %{count}"
|
25
26
|
less_than_or_equal_to: "must be less than or equal to %{count}"
|
27
|
+
other_than: "must be other than %{count}"
|
26
28
|
odd: "must be odd"
|
27
29
|
even: "must be even"
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
|
3
|
+
# == Active \Model Basic \Model
|
4
|
+
#
|
5
|
+
# Includes the required interface for an object to interact with
|
6
|
+
# <tt>ActionPack</tt>, using different <tt>ActiveModel</tt> modules.
|
7
|
+
# It includes model name introspections, conversions, translations and
|
8
|
+
# validations. Besides that, it allows you to initialize the object with a
|
9
|
+
# hash of attributes, pretty much like <tt>ActiveRecord</tt> does.
|
10
|
+
#
|
11
|
+
# A minimal implementation could be:
|
12
|
+
#
|
13
|
+
# class Person
|
14
|
+
# include ActiveModel::Model
|
15
|
+
# attr_accessor :name, :age
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# person = Person.new(name: 'bob', age: '18')
|
19
|
+
# person.name # => 'bob'
|
20
|
+
# person.age # => 18
|
21
|
+
#
|
22
|
+
# Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt>
|
23
|
+
# to return +false+, which is the most common case. You may want to override
|
24
|
+
# it in your class to simulate a different scenario:
|
25
|
+
#
|
26
|
+
# class Person
|
27
|
+
# include ActiveModel::Model
|
28
|
+
# attr_accessor :id, :name
|
29
|
+
#
|
30
|
+
# def persisted?
|
31
|
+
# self.id == 1
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# person = Person.new(id: 1, name: 'bob')
|
36
|
+
# person.persisted? # => true
|
37
|
+
#
|
38
|
+
# Also, if for some reason you need to run code on <tt>initialize</tt>, make
|
39
|
+
# sure you call +super+ if you want the attributes hash initialization to
|
40
|
+
# happen.
|
41
|
+
#
|
42
|
+
# class Person
|
43
|
+
# include ActiveModel::Model
|
44
|
+
# attr_accessor :id, :name, :omg
|
45
|
+
#
|
46
|
+
# def initialize(attributes={})
|
47
|
+
# super
|
48
|
+
# @omg ||= true
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# person = Person.new(id: 1, name: 'bob')
|
53
|
+
# person.omg # => true
|
54
|
+
#
|
55
|
+
# For more detailed information on other functionalities available, please
|
56
|
+
# refer to the specific modules included in <tt>ActiveModel::Model</tt>
|
57
|
+
# (see below).
|
58
|
+
module Model
|
59
|
+
def self.included(base) #:nodoc:
|
60
|
+
base.class_eval do
|
61
|
+
extend ActiveModel::Naming
|
62
|
+
extend ActiveModel::Translation
|
63
|
+
include ActiveModel::Validations
|
64
|
+
include ActiveModel::Conversion
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Initializes a new model with the given +params+.
|
69
|
+
#
|
70
|
+
# class Person
|
71
|
+
# include ActiveModel::Model
|
72
|
+
# attr_accessor :name, :age
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# person = Person.new(name: 'bob', age: '18')
|
76
|
+
# person.name # => "bob"
|
77
|
+
# person.age # => 18
|
78
|
+
def initialize(params={})
|
79
|
+
params.each do |attr, value|
|
80
|
+
self.public_send("#{attr}=", value)
|
81
|
+
end if params
|
82
|
+
end
|
83
|
+
|
84
|
+
# Indicates if the model is persisted. Default is +false+.
|
85
|
+
#
|
86
|
+
# class Person
|
87
|
+
# include ActiveModel::Model
|
88
|
+
# attr_accessor :id, :name
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# person = Person.new(id: 1, name: 'bob')
|
92
|
+
# person.persisted? # => false
|
93
|
+
def persisted?
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/active_model/naming.rb
CHANGED
@@ -1,43 +1,173 @@
|
|
1
|
-
require 'active_support/inflector'
|
2
1
|
require 'active_support/core_ext/hash/except'
|
3
2
|
require 'active_support/core_ext/module/introspection'
|
4
|
-
require 'active_support/deprecation'
|
5
3
|
|
6
4
|
module ActiveModel
|
7
|
-
class Name
|
8
|
-
|
9
|
-
|
5
|
+
class Name
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
attr_reader :singular, :plural, :element, :collection,
|
9
|
+
:singular_route_key, :route_key, :param_key, :i18n_key,
|
10
|
+
:name
|
10
11
|
|
11
12
|
alias_method :cache_key, :collection
|
12
13
|
|
13
|
-
|
14
|
+
##
|
15
|
+
# :method: ==
|
16
|
+
#
|
17
|
+
# :call-seq:
|
18
|
+
# ==(other)
|
19
|
+
#
|
20
|
+
# Equivalent to <tt>String#==</tt>. Returns +true+ if the class name and
|
21
|
+
# +other+ are equal, otherwise +false+.
|
22
|
+
#
|
23
|
+
# class BlogPost
|
24
|
+
# extend ActiveModel::Naming
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# BlogPost.model_name == 'BlogPost' # => true
|
28
|
+
# BlogPost.model_name == 'Blog Post' # => false
|
14
29
|
|
15
|
-
|
16
|
-
|
30
|
+
##
|
31
|
+
# :method: ===
|
32
|
+
#
|
33
|
+
# :call-seq:
|
34
|
+
# ===(other)
|
35
|
+
#
|
36
|
+
# Equivalent to <tt>#==</tt>.
|
37
|
+
#
|
38
|
+
# class BlogPost
|
39
|
+
# extend ActiveModel::Naming
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# BlogPost.model_name === 'BlogPost' # => true
|
43
|
+
# BlogPost.model_name === 'Blog Post' # => false
|
17
44
|
|
18
|
-
|
45
|
+
##
|
46
|
+
# :method: <=>
|
47
|
+
#
|
48
|
+
# :call-seq:
|
49
|
+
# ==(other)
|
50
|
+
#
|
51
|
+
# Equivalent to <tt>String#<=></tt>.
|
52
|
+
#
|
53
|
+
# class BlogPost
|
54
|
+
# extend ActiveModel::Naming
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# BlogPost.model_name <=> 'BlogPost' # => 0
|
58
|
+
# BlogPost.model_name <=> 'Blog' # => 1
|
59
|
+
# BlogPost.model_name <=> 'BlogPosts' # => -1
|
60
|
+
|
61
|
+
##
|
62
|
+
# :method: =~
|
63
|
+
#
|
64
|
+
# :call-seq:
|
65
|
+
# =~(regexp)
|
66
|
+
#
|
67
|
+
# Equivalent to <tt>String#=~</tt>. Match the class name against the given
|
68
|
+
# regexp. Returns the position where the match starts or +nil+ if there is
|
69
|
+
# no match.
|
70
|
+
#
|
71
|
+
# class BlogPost
|
72
|
+
# extend ActiveModel::Naming
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# BlogPost.model_name =~ /Post/ # => 4
|
76
|
+
# BlogPost.model_name =~ /\d/ # => nil
|
19
77
|
|
20
|
-
|
78
|
+
##
|
79
|
+
# :method: !~
|
80
|
+
#
|
81
|
+
# :call-seq:
|
82
|
+
# !~(regexp)
|
83
|
+
#
|
84
|
+
# Equivalent to <tt>String#!~</tt>. Match the class name against the given
|
85
|
+
# regexp. Returns +true+ if there is no match, otherwise +false+.
|
86
|
+
#
|
87
|
+
# class BlogPost
|
88
|
+
# extend ActiveModel::Naming
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# BlogPost.model_name !~ /Post/ # => false
|
92
|
+
# BlogPost.model_name !~ /\d/ # => true
|
21
93
|
|
22
|
-
|
94
|
+
##
|
95
|
+
# :method: eql?
|
96
|
+
#
|
97
|
+
# :call-seq:
|
98
|
+
# eql?(other)
|
99
|
+
#
|
100
|
+
# Equivalent to <tt>String#eql?</tt>. Returns +true+ if the class name and
|
101
|
+
# +other+ have the same length and content, otherwise +false+.
|
102
|
+
#
|
103
|
+
# class BlogPost
|
104
|
+
# extend ActiveModel::Naming
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# BlogPost.model_name.eql?('BlogPost') # => true
|
108
|
+
# BlogPost.model_name.eql?('Blog Post') # => false
|
109
|
+
|
110
|
+
##
|
111
|
+
# :method: to_s
|
112
|
+
#
|
113
|
+
# :call-seq:
|
114
|
+
# to_s()
|
115
|
+
#
|
116
|
+
# Returns the class name.
|
117
|
+
#
|
118
|
+
# class BlogPost
|
119
|
+
# extend ActiveModel::Naming
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# BlogPost.model_name.to_s # => "BlogPost"
|
123
|
+
|
124
|
+
##
|
125
|
+
# :method: to_str
|
126
|
+
#
|
127
|
+
# :call-seq:
|
128
|
+
# to_str()
|
129
|
+
#
|
130
|
+
# Equivalent to +to_s+.
|
131
|
+
delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s,
|
132
|
+
:to_str, :to => :name
|
133
|
+
|
134
|
+
# Returns a new ActiveModel::Name instance. By default, the +namespace+
|
135
|
+
# and +name+ option will take the namespace and name of the given class
|
136
|
+
# respectively.
|
137
|
+
#
|
138
|
+
# module Foo
|
139
|
+
# class Bar
|
140
|
+
# end
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
# ActiveModel::Name.new(Foo::Bar).to_s
|
144
|
+
# # => "Foo::Bar"
|
145
|
+
def initialize(klass, namespace = nil, name = nil)
|
146
|
+
@name = name || klass.name
|
147
|
+
|
148
|
+
raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?
|
149
|
+
|
150
|
+
@unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace
|
23
151
|
@klass = klass
|
24
|
-
@singular = _singularize(
|
25
|
-
@plural = ActiveSupport::Inflector.pluralize(@singular)
|
26
|
-
@element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(
|
27
|
-
@human = ActiveSupport::Inflector.humanize(@element)
|
28
|
-
@collection = ActiveSupport::Inflector.tableize(
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@i18n_key = self.underscore.to_sym
|
152
|
+
@singular = _singularize(@name)
|
153
|
+
@plural = ActiveSupport::Inflector.pluralize(@singular)
|
154
|
+
@element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(@name))
|
155
|
+
@human = ActiveSupport::Inflector.humanize(@element)
|
156
|
+
@collection = ActiveSupport::Inflector.tableize(@name)
|
157
|
+
@param_key = (namespace ? _singularize(@unnamespaced) : @singular)
|
158
|
+
@i18n_key = @name.underscore.to_sym
|
32
159
|
|
33
160
|
@route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural.dup)
|
34
|
-
@singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
|
161
|
+
@singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
|
35
162
|
@route_key << "_index" if @plural == @singular
|
36
|
-
@route_key.freeze
|
37
163
|
end
|
38
164
|
|
39
165
|
# Transform the model name into a more humane format, using I18n. By default,
|
40
|
-
# it will underscore then humanize the class name
|
166
|
+
# it will underscore then humanize the class name.
|
167
|
+
#
|
168
|
+
# class BlogPost
|
169
|
+
# extend ActiveModel::Naming
|
170
|
+
# end
|
41
171
|
#
|
42
172
|
# BlogPost.model_name.human # => "Blog post"
|
43
173
|
#
|
@@ -53,7 +183,7 @@ module ActiveModel
|
|
53
183
|
defaults << options[:default] if options[:default]
|
54
184
|
defaults << @human
|
55
185
|
|
56
|
-
options = {:scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults}.merge(options.except(:default))
|
186
|
+
options = { :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults }.merge!(options.except(:default))
|
57
187
|
I18n.translate(defaults.shift, options)
|
58
188
|
end
|
59
189
|
|
@@ -64,7 +194,7 @@ module ActiveModel
|
|
64
194
|
end
|
65
195
|
end
|
66
196
|
|
67
|
-
# == Active Model Naming
|
197
|
+
# == Active \Model \Naming
|
68
198
|
#
|
69
199
|
# Creates a +model_name+ method on your object.
|
70
200
|
#
|
@@ -81,11 +211,20 @@ module ActiveModel
|
|
81
211
|
# BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
|
82
212
|
#
|
83
213
|
# Providing the functionality that ActiveModel::Naming provides in your object
|
84
|
-
# is required to pass the Active Model Lint test. So either extending the
|
85
|
-
# method below, or rolling your own is required.
|
214
|
+
# is required to pass the Active Model Lint test. So either extending the
|
215
|
+
# provided method below, or rolling your own is required.
|
86
216
|
module Naming
|
87
217
|
# Returns an ActiveModel::Name object for module. It can be
|
88
|
-
# used to retrieve all kinds of naming-related information
|
218
|
+
# used to retrieve all kinds of naming-related information
|
219
|
+
# (See ActiveModel::Name for more information).
|
220
|
+
#
|
221
|
+
# class Person < ActiveModel::Model
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# Person.model_name # => Person
|
225
|
+
# Person.model_name.class # => ActiveModel::Name
|
226
|
+
# Person.model_name.singular # => "person"
|
227
|
+
# Person.model_name.plural # => "people"
|
89
228
|
def model_name
|
90
229
|
@_model_name ||= begin
|
91
230
|
namespace = self.parents.detect do |n|
|
@@ -95,7 +234,7 @@ module ActiveModel
|
|
95
234
|
end
|
96
235
|
end
|
97
236
|
|
98
|
-
# Returns the plural class name of a record or class.
|
237
|
+
# Returns the plural class name of a record or class.
|
99
238
|
#
|
100
239
|
# ActiveModel::Naming.plural(post) # => "posts"
|
101
240
|
# ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
|
@@ -103,7 +242,7 @@ module ActiveModel
|
|
103
242
|
model_name_from_record_or_class(record_or_class).plural
|
104
243
|
end
|
105
244
|
|
106
|
-
# Returns the singular class name of a record or class.
|
245
|
+
# Returns the singular class name of a record or class.
|
107
246
|
#
|
108
247
|
# ActiveModel::Naming.singular(post) # => "post"
|
109
248
|
# ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
|
@@ -111,10 +250,10 @@ module ActiveModel
|
|
111
250
|
model_name_from_record_or_class(record_or_class).singular
|
112
251
|
end
|
113
252
|
|
114
|
-
# Identifies whether the class name of a record or class is uncountable.
|
253
|
+
# Identifies whether the class name of a record or class is uncountable.
|
115
254
|
#
|
116
255
|
# ActiveModel::Naming.uncountable?(Sheep) # => true
|
117
|
-
# ActiveModel::Naming.uncountable?(Post) => false
|
256
|
+
# ActiveModel::Naming.uncountable?(Post) # => false
|
118
257
|
def self.uncountable?(record_or_class)
|
119
258
|
plural(record_or_class) == singular(record_or_class)
|
120
259
|
end
|
@@ -122,11 +261,11 @@ module ActiveModel
|
|
122
261
|
# Returns string to use while generating route names. It differs for
|
123
262
|
# namespaced models regarding whether it's inside isolated engine.
|
124
263
|
#
|
125
|
-
# For isolated engine:
|
126
|
-
#
|
264
|
+
# # For isolated engine:
|
265
|
+
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> post
|
127
266
|
#
|
128
|
-
# For shared engine:
|
129
|
-
#
|
267
|
+
# # For shared engine:
|
268
|
+
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> blog_post
|
130
269
|
def self.singular_route_key(record_or_class)
|
131
270
|
model_name_from_record_or_class(record_or_class).singular_route_key
|
132
271
|
end
|
@@ -134,11 +273,11 @@ module ActiveModel
|
|
134
273
|
# Returns string to use while generating route names. It differs for
|
135
274
|
# namespaced models regarding whether it's inside isolated engine.
|
136
275
|
#
|
137
|
-
# For isolated engine:
|
138
|
-
#
|
276
|
+
# # For isolated engine:
|
277
|
+
# ActiveModel::Naming.route_key(Blog::Post) #=> posts
|
139
278
|
#
|
140
|
-
# For shared engine:
|
141
|
-
#
|
279
|
+
# # For shared engine:
|
280
|
+
# ActiveModel::Naming.route_key(Blog::Post) #=> blog_posts
|
142
281
|
#
|
143
282
|
# The route key also considers if the noun is uncountable and, in
|
144
283
|
# such cases, automatically appends _index.
|
@@ -149,23 +288,24 @@ module ActiveModel
|
|
149
288
|
# Returns string to use for params names. It differs for
|
150
289
|
# namespaced models regarding whether it's inside isolated engine.
|
151
290
|
#
|
152
|
-
# For isolated engine:
|
153
|
-
#
|
291
|
+
# # For isolated engine:
|
292
|
+
# ActiveModel::Naming.param_key(Blog::Post) #=> post
|
154
293
|
#
|
155
|
-
# For shared engine:
|
156
|
-
#
|
294
|
+
# # For shared engine:
|
295
|
+
# ActiveModel::Naming.param_key(Blog::Post) #=> blog_post
|
157
296
|
def self.param_key(record_or_class)
|
158
297
|
model_name_from_record_or_class(record_or_class).param_key
|
159
298
|
end
|
160
299
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
300
|
+
def self.model_name_from_record_or_class(record_or_class) #:nodoc:
|
301
|
+
if record_or_class.respond_to?(:model_name)
|
302
|
+
record_or_class.model_name
|
303
|
+
elsif record_or_class.respond_to?(:to_model)
|
304
|
+
record_or_class.to_model.class.model_name
|
305
|
+
else
|
306
|
+
record_or_class.class.model_name
|
168
307
|
end
|
308
|
+
end
|
309
|
+
private_class_method :model_name_from_record_or_class
|
169
310
|
end
|
170
|
-
|
171
311
|
end
|