elasticsearch-persistence 5.1.0 → 6.0.0.pre
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/.rspec +2 -0
- data/Gemfile +9 -0
- data/README.md +164 -323
- data/Rakefile +8 -8
- data/elasticsearch-persistence.gemspec +4 -5
- data/lib/elasticsearch/persistence.rb +2 -110
- data/lib/elasticsearch/persistence/repository.rb +212 -53
- data/lib/elasticsearch/persistence/repository/dsl.rb +94 -0
- data/lib/elasticsearch/persistence/repository/find.rb +27 -10
- data/lib/elasticsearch/persistence/repository/response/results.rb +17 -5
- data/lib/elasticsearch/persistence/repository/search.rb +15 -4
- data/lib/elasticsearch/persistence/repository/serialize.rb +65 -7
- data/lib/elasticsearch/persistence/repository/store.rb +38 -44
- data/lib/elasticsearch/persistence/version.rb +1 -1
- data/spec/repository/find_spec.rb +179 -0
- data/spec/repository/response/results_spec.rb +105 -0
- data/spec/repository/search_spec.rb +181 -0
- data/spec/repository/serialize_spec.rb +53 -0
- data/spec/repository/store_spec.rb +327 -0
- data/spec/repository_spec.rb +716 -0
- data/spec/spec_helper.rb +28 -0
- metadata +25 -80
- data/lib/elasticsearch/persistence/client.rb +0 -51
- data/lib/elasticsearch/persistence/model.rb +0 -153
- data/lib/elasticsearch/persistence/model/base.rb +0 -87
- data/lib/elasticsearch/persistence/model/errors.rb +0 -8
- data/lib/elasticsearch/persistence/model/find.rb +0 -180
- data/lib/elasticsearch/persistence/model/rails.rb +0 -47
- data/lib/elasticsearch/persistence/model/store.rb +0 -254
- data/lib/elasticsearch/persistence/model/utils.rb +0 -0
- data/lib/elasticsearch/persistence/repository/class.rb +0 -71
- data/lib/elasticsearch/persistence/repository/naming.rb +0 -115
- data/lib/rails/generators/elasticsearch/model/model_generator.rb +0 -21
- data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +0 -9
- data/lib/rails/generators/elasticsearch_generator.rb +0 -2
- data/test/integration/model/model_basic_test.rb +0 -238
- data/test/integration/repository/custom_class_test.rb +0 -85
- data/test/integration/repository/customized_class_test.rb +0 -82
- data/test/integration/repository/default_class_test.rb +0 -116
- data/test/integration/repository/virtus_model_test.rb +0 -118
- data/test/test_helper.rb +0 -55
- data/test/unit/model_base_test.rb +0 -72
- data/test/unit/model_find_test.rb +0 -153
- data/test/unit/model_gateway_test.rb +0 -101
- data/test/unit/model_rails_test.rb +0 -112
- data/test/unit/model_store_test.rb +0 -576
- data/test/unit/persistence_test.rb +0 -32
- data/test/unit/repository_class_test.rb +0 -51
- data/test/unit/repository_client_test.rb +0 -32
- data/test/unit/repository_find_test.rb +0 -388
- data/test/unit/repository_indexing_test.rb +0 -37
- data/test/unit/repository_module_test.rb +0 -146
- data/test/unit/repository_naming_test.rb +0 -146
- data/test/unit/repository_response_results_test.rb +0 -98
- data/test/unit/repository_search_test.rb +0 -117
- data/test/unit/repository_serialize_test.rb +0 -57
- data/test/unit/repository_store_test.rb +0 -303
@@ -1,180 +0,0 @@
|
|
1
|
-
module Elasticsearch
|
2
|
-
module Persistence
|
3
|
-
module Model
|
4
|
-
|
5
|
-
module Find
|
6
|
-
class SearchRequest < Elasticsearch::Model::Searching::SearchRequest
|
7
|
-
def execute!
|
8
|
-
klass.gateway.search(definition[:body] || definition[:q], options)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
|
14
|
-
def search(query_or_definition, options={})
|
15
|
-
SearchRequest.new(self, query_or_definition, options).execute!
|
16
|
-
end
|
17
|
-
|
18
|
-
# Returns all models (up to 10,000)
|
19
|
-
#
|
20
|
-
# @example Retrieve all people
|
21
|
-
#
|
22
|
-
# Person.all
|
23
|
-
# # => [#<Person:0x007ff1d8fb04b0 ... ]
|
24
|
-
#
|
25
|
-
# @example Retrieve all people matching a query
|
26
|
-
#
|
27
|
-
# Person.all query: { match: { last_name: 'Smith' } }
|
28
|
-
# # => [#<Person:0x007ff1d8fb04b0 ... ]
|
29
|
-
#
|
30
|
-
def all(query={ query: { match_all: {} } }, options={})
|
31
|
-
query[:size] ||= 10_000
|
32
|
-
search(query, options)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns the number of models
|
36
|
-
#
|
37
|
-
# @example Return the count of all models
|
38
|
-
#
|
39
|
-
# Person.count
|
40
|
-
# # => 2
|
41
|
-
#
|
42
|
-
# @example Return the count of models matching a simple query
|
43
|
-
#
|
44
|
-
# Person.count('fox or dog')
|
45
|
-
# # => 1
|
46
|
-
#
|
47
|
-
# @example Return the count of models matching a query in the Elasticsearch DSL
|
48
|
-
#
|
49
|
-
# Person.search(query: { match: { title: 'fox dog' } })
|
50
|
-
# # => 1
|
51
|
-
#
|
52
|
-
# @return [Integer]
|
53
|
-
#
|
54
|
-
def count(query_or_definition=nil, options={})
|
55
|
-
gateway.count( query_or_definition, options )
|
56
|
-
end
|
57
|
-
|
58
|
-
# Returns all models efficiently via the Elasticsearch's scroll API
|
59
|
-
#
|
60
|
-
# You can restrict the models being returned with a query.
|
61
|
-
#
|
62
|
-
# The {http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions#search-instance_method Search API}
|
63
|
-
# options are passed to the search method as parameters, all remaining options are passed
|
64
|
-
# as the `:body` parameter.
|
65
|
-
#
|
66
|
-
# The full {Persistence::Repository::Response::Results} instance is yielded to the passed
|
67
|
-
# block in each batch, so you can access any of its properties; calling `to_a` will
|
68
|
-
# convert the object to an Array of model instances.
|
69
|
-
#
|
70
|
-
# @example Return all models in batches of 20 x number of primary shards
|
71
|
-
#
|
72
|
-
# Person.find_in_batches { |batch| puts batch.map(&:name) }
|
73
|
-
#
|
74
|
-
# @example Return all models in batches of 100 x number of primary shards
|
75
|
-
#
|
76
|
-
# Person.find_in_batches(size: 100) { |batch| puts batch.map(&:name) }
|
77
|
-
#
|
78
|
-
# @example Return all models matching a specific query
|
79
|
-
#
|
80
|
-
# Person.find_in_batches(query: { match: { name: 'test' } }) { |batch| puts batch.map(&:name) }
|
81
|
-
#
|
82
|
-
# @example Return all models, fetching only the `name` attribute from Elasticsearch
|
83
|
-
#
|
84
|
-
# Person.find_in_batches( _source_include: 'name') { |_| puts _.response.hits.hits.map(&:to_hash) }
|
85
|
-
#
|
86
|
-
# @example Leave out the block to return an Enumerator instance
|
87
|
-
#
|
88
|
-
# Person.find_in_batches(size: 100).map { |batch| batch.size }
|
89
|
-
# # => [100, 100, 100, ... ]
|
90
|
-
#
|
91
|
-
# @return [String,Enumerator] The `scroll_id` for the request or Enumerator when the block is not passed
|
92
|
-
#
|
93
|
-
def find_in_batches(options={}, &block)
|
94
|
-
return to_enum(:find_in_batches, options) unless block_given?
|
95
|
-
|
96
|
-
search_params = options.extract!(
|
97
|
-
:index,
|
98
|
-
:type,
|
99
|
-
:scroll,
|
100
|
-
:size,
|
101
|
-
:explain,
|
102
|
-
:ignore_indices,
|
103
|
-
:ignore_unavailable,
|
104
|
-
:allow_no_indices,
|
105
|
-
:expand_wildcards,
|
106
|
-
:preference,
|
107
|
-
:q,
|
108
|
-
:routing,
|
109
|
-
:source,
|
110
|
-
:_source,
|
111
|
-
:_source_include,
|
112
|
-
:_source_exclude,
|
113
|
-
:stats,
|
114
|
-
:timeout)
|
115
|
-
|
116
|
-
scroll = search_params.delete(:scroll) || '5m'
|
117
|
-
|
118
|
-
body = options
|
119
|
-
|
120
|
-
# Get the initial batch of documents and the scroll_id
|
121
|
-
#
|
122
|
-
response = gateway.client.search( {
|
123
|
-
index: gateway.index_name,
|
124
|
-
type: gateway.document_type,
|
125
|
-
scroll: scroll,
|
126
|
-
sort: ['_doc'],
|
127
|
-
size: 20,
|
128
|
-
body: body }.merge(search_params) )
|
129
|
-
|
130
|
-
|
131
|
-
# Scroll the search object and break when receiving an empty array of hits
|
132
|
-
#
|
133
|
-
while response['hits']['hits'].any? do
|
134
|
-
yield Repository::Response::Results.new(gateway, response)
|
135
|
-
|
136
|
-
response = gateway.client.scroll( { scroll_id: response['_scroll_id'], scroll: scroll } )
|
137
|
-
end
|
138
|
-
|
139
|
-
return response['_scroll_id']
|
140
|
-
end
|
141
|
-
|
142
|
-
# Iterate effectively over models using the `find_in_batches` method.
|
143
|
-
#
|
144
|
-
# All the options are passed to `find_in_batches` and each result is yielded to the passed block.
|
145
|
-
#
|
146
|
-
# @example Print out the people's names by scrolling through the index
|
147
|
-
#
|
148
|
-
# Person.find_each { |person| puts person.name }
|
149
|
-
#
|
150
|
-
# # # GET http://localhost:9200/people/person/_search?scroll=5m&size=20
|
151
|
-
# # # GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhbj...
|
152
|
-
# # Test 0
|
153
|
-
# # Test 1
|
154
|
-
# # Test 2
|
155
|
-
# # ...
|
156
|
-
# # # GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhbj...
|
157
|
-
# # Test 20
|
158
|
-
# # Test 21
|
159
|
-
# # Test 22
|
160
|
-
#
|
161
|
-
# @example Leave out the block to return an Enumerator instance
|
162
|
-
#
|
163
|
-
# Person.find_each.select { |person| person.name =~ /John/ }
|
164
|
-
# # => => [#<Person {id: "NkltJP5vRxqk9_RMP7SU8Q", name: "John Smith", ...}>]
|
165
|
-
#
|
166
|
-
# @return [String,Enumerator] The `scroll_id` for the request or Enumerator when the block is not passed
|
167
|
-
#
|
168
|
-
def find_each(options = {})
|
169
|
-
return to_enum(:find_each, options) unless block_given?
|
170
|
-
|
171
|
-
find_in_batches(options) do |batch|
|
172
|
-
batch.each { |result| yield result }
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Elasticsearch
|
2
|
-
module Persistence
|
3
|
-
module Model
|
4
|
-
|
5
|
-
# Make the `Persistence::Model` models compatible with Ruby On Rails applications
|
6
|
-
#
|
7
|
-
module Rails
|
8
|
-
def self.included(base)
|
9
|
-
base.class_eval do
|
10
|
-
|
11
|
-
def initialize(attributes={})
|
12
|
-
super(__convert_rails_dates(attributes))
|
13
|
-
end
|
14
|
-
|
15
|
-
def update(attributes={}, options={})
|
16
|
-
super(__convert_rails_dates(attributes), options)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Decorates the passed in `attributes` so they extract the date & time values from Rails forms
|
22
|
-
#
|
23
|
-
# @example Correctly combine the date and time to a datetime string
|
24
|
-
#
|
25
|
-
# params = { "published_on(1i)"=>"2014",
|
26
|
-
# "published_on(2i)"=>"1",
|
27
|
-
# "published_on(3i)"=>"1",
|
28
|
-
# "published_on(4i)"=>"12",
|
29
|
-
# "published_on(5i)"=>"00"
|
30
|
-
# }
|
31
|
-
# MyRailsModel.new(params).published_on.iso8601
|
32
|
-
# # => "2014-01-01T12:00:00+00:00"
|
33
|
-
#
|
34
|
-
def __convert_rails_dates(attributes={})
|
35
|
-
day = attributes.select { |p| p =~ /\([1-3]/ }.reduce({}) { |sum, item| (sum[item.first.gsub(/\(.+\)/, '')] ||= '' )<< item.last+'-'; sum }
|
36
|
-
time = attributes.select { |p| p =~ /\([4-6]/ }.reduce({}) { |sum, item| (sum[item.first.gsub(/\(.+\)/, '')] ||= '' )<< item.last+':'; sum }
|
37
|
-
unless day.empty?
|
38
|
-
attributes.update day.reduce({}) { |sum, item| sum[item.first] = item.last; sum[item.first] += ' ' + time[item.first] unless time.empty?; sum }
|
39
|
-
end
|
40
|
-
|
41
|
-
return attributes
|
42
|
-
end; module_function :__convert_rails_dates
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,254 +0,0 @@
|
|
1
|
-
module Elasticsearch
|
2
|
-
module Persistence
|
3
|
-
module Model
|
4
|
-
|
5
|
-
# This module contains the storage related features of {Elasticsearch::Persistence::Model}
|
6
|
-
#
|
7
|
-
module Store
|
8
|
-
module ClassMethods #:nodoc:
|
9
|
-
|
10
|
-
# Creates a class instance, saves it, if validations pass, and returns it
|
11
|
-
#
|
12
|
-
# @example Create a new person
|
13
|
-
#
|
14
|
-
# Person.create name: 'John Smith'
|
15
|
-
# # => #<Person:0x007f889e302b30 ... @id="bG7yQDAXRhCi3ZfVcx6oAA", @name="John Smith" ...>
|
16
|
-
#
|
17
|
-
# @return [Object] The model instance
|
18
|
-
#
|
19
|
-
def create(attributes, options={})
|
20
|
-
object = self.new(attributes)
|
21
|
-
object.run_callbacks :create do
|
22
|
-
object.save(options)
|
23
|
-
object
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
module InstanceMethods
|
29
|
-
|
30
|
-
# Saves the model (if validations pass) and returns the response (or `false`)
|
31
|
-
#
|
32
|
-
# @example Save a valid model instance
|
33
|
-
#
|
34
|
-
# p = Person.new(name: 'John')
|
35
|
-
# p.save
|
36
|
-
# => {"_index"=>"people", ... "_id"=>"RzFSXFR0R8u1CZIWNs2Gvg", "_version"=>1, "created"=>true}
|
37
|
-
#
|
38
|
-
# @example Save an invalid model instance
|
39
|
-
#
|
40
|
-
# p = Person.new(name: nil)
|
41
|
-
# p.save
|
42
|
-
# # => false
|
43
|
-
#
|
44
|
-
# @return [Hash,FalseClass] The Elasticsearch response as a Hash or `false`
|
45
|
-
#
|
46
|
-
def save(options={})
|
47
|
-
unless options.delete(:validate) == false
|
48
|
-
return false unless valid?
|
49
|
-
end
|
50
|
-
|
51
|
-
run_callbacks :save do
|
52
|
-
options.update id: self.id
|
53
|
-
options.update index: self._index if self._index
|
54
|
-
options.update type: self._type if self._type
|
55
|
-
|
56
|
-
self[:updated_at] = Time.now.utc
|
57
|
-
|
58
|
-
response = self.class.gateway.save(self, options)
|
59
|
-
|
60
|
-
@_id = response['_id']
|
61
|
-
@_index = response['_index']
|
62
|
-
@_type = response['_type']
|
63
|
-
@_version = response['_version']
|
64
|
-
@persisted = true
|
65
|
-
|
66
|
-
response
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Deletes the model from Elasticsearch (if it's persisted), freezes it, and returns the response
|
71
|
-
#
|
72
|
-
# @example Delete a model instance
|
73
|
-
#
|
74
|
-
# p.destroy
|
75
|
-
# => {"_index"=>"people", ... "_id"=>"RzFSXFR0R8u1CZIWNs2Gvg", "_version"=>2 ...}
|
76
|
-
#
|
77
|
-
# @return [Hash] The Elasticsearch response as a Hash
|
78
|
-
#
|
79
|
-
def destroy(options={})
|
80
|
-
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
81
|
-
|
82
|
-
run_callbacks :destroy do
|
83
|
-
options.update index: self._index if self._index
|
84
|
-
options.update type: self._type if self._type
|
85
|
-
|
86
|
-
response = self.class.gateway.delete(self.id, options)
|
87
|
-
|
88
|
-
@destroyed = true
|
89
|
-
@persisted = false
|
90
|
-
self.freeze
|
91
|
-
response
|
92
|
-
end
|
93
|
-
end; alias :delete :destroy
|
94
|
-
|
95
|
-
# Updates the model (via Elasticsearch's "Update" API) and returns the response
|
96
|
-
#
|
97
|
-
# @example Update a model with partial attributes
|
98
|
-
#
|
99
|
-
# p.update name: 'UPDATED'
|
100
|
-
# => {"_index"=>"people", ... "_version"=>2}
|
101
|
-
#
|
102
|
-
# @example Pass a version for concurrency control
|
103
|
-
#
|
104
|
-
# p.update( { name: 'UPDATED' }, { version: 2 } )
|
105
|
-
# => {"_index"=>"people", ... "_version"=>3}
|
106
|
-
#
|
107
|
-
# @example An exception is raised when the version doesn't match
|
108
|
-
#
|
109
|
-
# p.update( { name: 'UPDATED' }, { version: 2 } )
|
110
|
-
# => Elasticsearch::Transport::Transport::Errors::Conflict: [409] {"error" ... }
|
111
|
-
#
|
112
|
-
# @return [Hash] The Elasticsearch response as a Hash
|
113
|
-
#
|
114
|
-
def update(attributes={}, options={})
|
115
|
-
unless options.delete(:validate) == false
|
116
|
-
return false unless valid?
|
117
|
-
end
|
118
|
-
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
119
|
-
|
120
|
-
run_callbacks :update do
|
121
|
-
options.update index: self._index if self._index
|
122
|
-
options.update type: self._type if self._type
|
123
|
-
|
124
|
-
attributes.update( { updated_at: Time.now.utc } )
|
125
|
-
response = self.class.gateway.update(self.id, { doc: attributes}.merge(options))
|
126
|
-
|
127
|
-
self.attributes = self.attributes.merge(attributes)
|
128
|
-
@_index = response['_index']
|
129
|
-
@_type = response['_type']
|
130
|
-
@_version = response['_version']
|
131
|
-
|
132
|
-
response
|
133
|
-
end
|
134
|
-
end; alias :update_attributes :update
|
135
|
-
|
136
|
-
# Increments a numeric attribute (via Elasticsearch's "Update" API) and returns the response
|
137
|
-
#
|
138
|
-
# @example Increment the `salary` attribute by 1
|
139
|
-
#
|
140
|
-
# p.increment :salary
|
141
|
-
#
|
142
|
-
# @example Increment the `salary` attribute by 100
|
143
|
-
#
|
144
|
-
# p.increment :salary, 100
|
145
|
-
#
|
146
|
-
# @return [Hash] The Elasticsearch response as a Hash
|
147
|
-
#
|
148
|
-
def increment(attribute, value=1, options={})
|
149
|
-
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
150
|
-
|
151
|
-
options.update index: self._index if self._index
|
152
|
-
options.update type: self._type if self._type
|
153
|
-
|
154
|
-
response = self.class.gateway.update(self.id, { script: "ctx._source.#{attribute} += #{value}"}.merge(options))
|
155
|
-
|
156
|
-
self[attribute] += value
|
157
|
-
|
158
|
-
@_index = response['_index']
|
159
|
-
@_type = response['_type']
|
160
|
-
@_version = response['_version']
|
161
|
-
|
162
|
-
response
|
163
|
-
end
|
164
|
-
|
165
|
-
# Decrements a numeric attribute (via Elasticsearch's "Update" API) and returns the response
|
166
|
-
#
|
167
|
-
# @example Decrement the `salary` attribute by 1
|
168
|
-
#
|
169
|
-
# p.decrement :salary
|
170
|
-
#
|
171
|
-
# @example Decrement the `salary` attribute by 100
|
172
|
-
#
|
173
|
-
# p.decrement :salary, 100
|
174
|
-
#
|
175
|
-
# @return [Hash] The Elasticsearch response as a Hash
|
176
|
-
#
|
177
|
-
def decrement(attribute, value=1, options={})
|
178
|
-
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
179
|
-
|
180
|
-
options.update index: self._index if self._index
|
181
|
-
options.update type: self._type if self._type
|
182
|
-
|
183
|
-
response = self.class.gateway.update(self.id, { script: "ctx._source.#{attribute} = ctx._source.#{attribute} - #{value}"}.merge(options))
|
184
|
-
self[attribute] -= value
|
185
|
-
|
186
|
-
@_index = response['_index']
|
187
|
-
@_type = response['_type']
|
188
|
-
@_version = response['_version']
|
189
|
-
|
190
|
-
response
|
191
|
-
end
|
192
|
-
|
193
|
-
# Updates the `updated_at` attribute, saves the model and returns the response
|
194
|
-
#
|
195
|
-
# @example Update the `updated_at` attribute (default)
|
196
|
-
#
|
197
|
-
# p.touch
|
198
|
-
#
|
199
|
-
# @example Update a custom attribute: `saved_on`
|
200
|
-
#
|
201
|
-
# p.touch :saved_on
|
202
|
-
#
|
203
|
-
# @return [Hash] The Elasticsearch response as a Hash
|
204
|
-
#
|
205
|
-
def touch(attribute=:updated_at, options={})
|
206
|
-
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
207
|
-
raise ArgumentError, "Object does not have '#{attribute}' attribute" unless respond_to?(attribute)
|
208
|
-
|
209
|
-
run_callbacks :touch do
|
210
|
-
options.update index: self._index if self._index
|
211
|
-
options.update type: self._type if self._type
|
212
|
-
|
213
|
-
value = Time.now.utc
|
214
|
-
response = self.class.gateway.update(self.id, { doc: { attribute => value.iso8601 }}.merge(options))
|
215
|
-
|
216
|
-
self[attribute] = value
|
217
|
-
|
218
|
-
@_index = response['_index']
|
219
|
-
@_type = response['_type']
|
220
|
-
@_version = response['_version']
|
221
|
-
|
222
|
-
response
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
# Returns true when the model has been destroyed, false otherwise
|
227
|
-
#
|
228
|
-
# @return [TrueClass,FalseClass]
|
229
|
-
#
|
230
|
-
def destroyed?
|
231
|
-
!!@destroyed
|
232
|
-
end
|
233
|
-
|
234
|
-
# Returns true when the model has been already saved to the database, false otherwise
|
235
|
-
#
|
236
|
-
# @return [TrueClass,FalseClass]
|
237
|
-
#
|
238
|
-
def persisted?
|
239
|
-
!!@persisted && !destroyed?
|
240
|
-
end
|
241
|
-
|
242
|
-
# Returns true when the model has not been saved yet, false otherwise
|
243
|
-
#
|
244
|
-
# @return [TrueClass,FalseClass]
|
245
|
-
#
|
246
|
-
def new_record?
|
247
|
-
!persisted? && !destroyed?
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|