activerecord 6.1.0.rc1 → 6.1.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +177 -20
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -4
- data/lib/active_record/association_relation.rb +10 -0
- data/lib/active_record/associations.rb +6 -2
- data/lib/active_record/associations/association.rb +14 -9
- data/lib/active_record/associations/association_scope.rb +7 -5
- data/lib/active_record/associations/belongs_to_association.rb +7 -3
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +23 -2
- data/lib/active_record/associations/builder/belongs_to.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +8 -7
- data/lib/active_record/attribute_methods.rb +13 -7
- data/lib/active_record/attribute_methods/serialization.rb +8 -2
- data/lib/active_record/attributes.rb +6 -1
- data/lib/active_record/callbacks.rb +121 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -3
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/abstract/transaction.rb +24 -18
- data/lib/active_record/connection_adapters/abstract_adapter.rb +23 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
- data/lib/active_record/connection_adapters/pool_config.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_handling.rb +11 -3
- data/lib/active_record/core.rb +51 -32
- data/lib/active_record/database_configurations/url_config.rb +1 -1
- data/lib/active_record/enum.rb +58 -31
- data/lib/active_record/fixtures.rb +4 -1
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +2 -0
- data/lib/active_record/internal_metadata.rb +2 -4
- data/lib/active_record/locking/optimistic.rb +14 -4
- data/lib/active_record/log_subscriber.rb +3 -2
- data/lib/active_record/migration/compatibility.rb +2 -1
- data/lib/active_record/model_schema.rb +29 -0
- data/lib/active_record/railtie.rb +2 -2
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +29 -7
- data/lib/active_record/reflection.rb +2 -1
- data/lib/active_record/relation/predicate_builder.rb +6 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +3 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +9 -5
- data/lib/active_record/relation/query_methods.rb +9 -6
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/schema_migration.rb +2 -4
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/table_metadata.rb +10 -3
- data/lib/active_record/tasks/database_tasks.rb +1 -0
- data/lib/active_record/transactions.rb +4 -2
- metadata +12 -12
@@ -773,9 +773,12 @@ module ActiveRecord
|
|
773
773
|
|
774
774
|
def find
|
775
775
|
raise FixtureClassNotFound, "No class attached to find." unless model_class
|
776
|
-
model_class.unscoped do
|
776
|
+
object = model_class.unscoped do
|
777
777
|
model_class.find(fixture[model_class.primary_key])
|
778
778
|
end
|
779
|
+
# Fixtures can't be eagerly loaded
|
780
|
+
object.instance_variable_set(:@strict_loading, false)
|
781
|
+
object
|
779
782
|
end
|
780
783
|
end
|
781
784
|
end
|
@@ -69,6 +69,8 @@ module ActiveRecord
|
|
69
69
|
attr_reader :scope_attributes
|
70
70
|
|
71
71
|
def find_unique_index_for(unique_by)
|
72
|
+
return unique_by if !connection.supports_insert_conflict_target?
|
73
|
+
|
72
74
|
name_or_columns = unique_by || model.primary_key
|
73
75
|
match = Array(name_or_columns).map(&:to_s)
|
74
76
|
|
@@ -43,11 +43,9 @@ module ActiveRecord
|
|
43
43
|
def create_table
|
44
44
|
return unless enabled?
|
45
45
|
|
46
|
-
unless table_exists?
|
47
|
-
key_options = connection.internal_string_options_for_primary_key
|
48
|
-
|
46
|
+
unless connection.table_exists?(table_name)
|
49
47
|
connection.create_table(table_name, id: false) do |t|
|
50
|
-
t.string :key, **
|
48
|
+
t.string :key, **connection.internal_string_options_for_primary_key
|
51
49
|
t.string :value
|
52
50
|
t.timestamps
|
53
51
|
end
|
@@ -89,7 +89,9 @@ module ActiveRecord
|
|
89
89
|
|
90
90
|
begin
|
91
91
|
locking_column = self.class.locking_column
|
92
|
-
|
92
|
+
lock_attribute_was = @attributes[locking_column]
|
93
|
+
lock_value_for_database = _lock_value_for_database(locking_column)
|
94
|
+
|
93
95
|
attribute_names = attribute_names.dup if attribute_names.frozen?
|
94
96
|
attribute_names << locking_column
|
95
97
|
|
@@ -98,7 +100,7 @@ module ActiveRecord
|
|
98
100
|
affected_rows = self.class._update_record(
|
99
101
|
attributes_with_values(attribute_names),
|
100
102
|
@primary_key => id_in_database,
|
101
|
-
locking_column =>
|
103
|
+
locking_column => lock_value_for_database
|
102
104
|
)
|
103
105
|
|
104
106
|
if affected_rows != 1
|
@@ -109,7 +111,7 @@ module ActiveRecord
|
|
109
111
|
|
110
112
|
# If something went wrong, revert the locking_column value.
|
111
113
|
rescue Exception
|
112
|
-
|
114
|
+
@attributes[locking_column] = lock_attribute_was
|
113
115
|
raise
|
114
116
|
end
|
115
117
|
end
|
@@ -121,7 +123,7 @@ module ActiveRecord
|
|
121
123
|
|
122
124
|
affected_rows = self.class._delete_record(
|
123
125
|
@primary_key => id_in_database,
|
124
|
-
locking_column =>
|
126
|
+
locking_column => _lock_value_for_database(locking_column)
|
125
127
|
)
|
126
128
|
|
127
129
|
if affected_rows != 1
|
@@ -131,6 +133,14 @@ module ActiveRecord
|
|
131
133
|
affected_rows
|
132
134
|
end
|
133
135
|
|
136
|
+
def _lock_value_for_database(locking_column)
|
137
|
+
if will_save_change_to_attribute?(locking_column)
|
138
|
+
@attributes[locking_column].value_for_database
|
139
|
+
else
|
140
|
+
@attributes[locking_column].original_value_for_database
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
134
144
|
module ClassMethods
|
135
145
|
DEFAULT_LOCKING_COLUMN = "lock_version"
|
136
146
|
|
@@ -22,9 +22,10 @@ module ActiveRecord
|
|
22
22
|
def strict_loading_violation(event)
|
23
23
|
debug do
|
24
24
|
owner = event.payload[:owner]
|
25
|
-
association = event.payload[:
|
25
|
+
association = event.payload[:reflection].klass
|
26
|
+
name = event.payload[:reflection].name
|
26
27
|
|
27
|
-
color("Strict loading violation: #{
|
28
|
+
color("Strict loading violation: #{owner} is marked for strict loading. The #{association} association named :#{name} cannot be lazily loaded.", RED)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -56,7 +56,8 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def add_reference(table_name, ref_name, **options)
|
59
|
-
ReferenceDefinition.new(ref_name, **options)
|
59
|
+
ReferenceDefinition.new(ref_name, **options)
|
60
|
+
.add_to(connection.update_table_definition(table_name, self))
|
60
61
|
end
|
61
62
|
alias :add_belongs_to :add_reference
|
62
63
|
|
@@ -297,6 +297,35 @@ module ActiveRecord
|
|
297
297
|
|
298
298
|
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
299
299
|
# accessors defined, and won't be referenced in SQL queries.
|
300
|
+
#
|
301
|
+
# A common usage pattern for this method is to ensure all references to an attribute
|
302
|
+
# have been removed and deployed, before a migration to drop the column from the database
|
303
|
+
# has been deployed and run. Using this two step approach to dropping columns ensures there
|
304
|
+
# is no code that raises errors due to having a cached schema in memory at the time the
|
305
|
+
# schema migration is run.
|
306
|
+
#
|
307
|
+
# For example, given a model where you want to drop the "category" attribute, first mark it
|
308
|
+
# as ignored:
|
309
|
+
#
|
310
|
+
# class Project < ActiveRecord::Base
|
311
|
+
# # schema:
|
312
|
+
# # id :bigint
|
313
|
+
# # name :string, limit: 255
|
314
|
+
# # category :string, limit: 255
|
315
|
+
#
|
316
|
+
# self.ignored_columns = [:category]
|
317
|
+
# end
|
318
|
+
#
|
319
|
+
# The schema still contains `category`, but now the model omits it, so any meta-driven code or
|
320
|
+
# schema caching will not attempt to use the column:
|
321
|
+
#
|
322
|
+
# Project.columns_hash["category"] => nil
|
323
|
+
#
|
324
|
+
# You will get an error if accessing that attribute directly, so ensure all usages of the
|
325
|
+
# column are removed (automated tests can help you find any usages).
|
326
|
+
#
|
327
|
+
# user = Project.create!(name: "First Project")
|
328
|
+
# user.category # => raises NoMethodError
|
300
329
|
def ignored_columns=(columns)
|
301
330
|
reload_schema_from_cache
|
302
331
|
@ignored_columns = columns.map(&:to_s).freeze
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
config.active_record.maintain_test_schema = true
|
32
32
|
config.active_record.has_many_inversing = false
|
33
33
|
|
34
|
-
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
34
|
+
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
35
35
|
|
36
36
|
config.eager_load_namespaces << ActiveRecord
|
37
37
|
|
@@ -183,7 +183,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
183
183
|
end
|
184
184
|
end
|
185
185
|
rescue ActiveRecordError => error
|
186
|
-
# Regardless of
|
186
|
+
# Regardless of whether there was already a connection or not, we rescue any database
|
187
187
|
# error because it is critical that the application can boot even if the database
|
188
188
|
# is unhealthy.
|
189
189
|
warn "Failed to define attribute methods because of #{error.class}: #{error.message}"
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
ActiveRecord::
|
4
|
-
|
5
|
-
at_exit do
|
6
|
-
ActiveRecord::Base.connection.rollback_transaction
|
3
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.set_callback(:checkout, :after) do
|
4
|
+
begin_transaction(joinable: false)
|
7
5
|
end
|
@@ -361,17 +361,23 @@ db_namespace = namespace :db do
|
|
361
361
|
|
362
362
|
# Skipped when no database
|
363
363
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
364
|
+
|
364
365
|
if ActiveRecord::Base.dump_schema_after_migration
|
365
366
|
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, ActiveRecord::Base.schema_format)
|
366
367
|
end
|
367
|
-
|
368
368
|
rescue ActiveRecord::NoDatabaseError
|
369
|
-
|
370
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
369
|
+
config_name = db_config.name
|
370
|
+
ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, config_name)
|
371
|
+
|
372
|
+
if File.exist?(ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_name))
|
373
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(
|
374
|
+
db_config,
|
375
|
+
ActiveRecord::Base.schema_format,
|
376
|
+
nil
|
377
|
+
)
|
378
|
+
else
|
379
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
380
|
+
end
|
375
381
|
|
376
382
|
seed = true
|
377
383
|
end
|
@@ -455,6 +461,14 @@ db_namespace = namespace :db do
|
|
455
461
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord::Base.schema_format, ENV["SCHEMA"])
|
456
462
|
end
|
457
463
|
|
464
|
+
task load_if_ruby: ["db:create", :environment] do
|
465
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
466
|
+
Using `bin/rails db:schema:load_if_ruby` is deprecated and will be removed in Rails 6.2.
|
467
|
+
Configure the format using `config.active_record.schema_format = :ruby` to use `schema.rb` and run `bin/rails db:schema:load` instead.
|
468
|
+
MSG
|
469
|
+
db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
|
470
|
+
end
|
471
|
+
|
458
472
|
namespace :dump do
|
459
473
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
460
474
|
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for #{name} database"
|
@@ -529,6 +543,14 @@ db_namespace = namespace :db do
|
|
529
543
|
db_namespace["schema:load"].invoke
|
530
544
|
end
|
531
545
|
|
546
|
+
task load_if_sql: ["db:create", :environment] do
|
547
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
548
|
+
Using `bin/rails db:structure:load_if_sql` is deprecated and will be removed in Rails 6.2.
|
549
|
+
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
|
550
|
+
MSG
|
551
|
+
db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :sql
|
552
|
+
end
|
553
|
+
|
532
554
|
namespace :dump do
|
533
555
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
534
556
|
desc "Dumps the #{name} database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
|
@@ -162,7 +162,7 @@ module ActiveRecord
|
|
162
162
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
163
163
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
164
164
|
def class_name
|
165
|
-
@class_name ||= -(options[:class_name]
|
165
|
+
@class_name ||= -(options[:class_name] || derive_class_name).to_s
|
166
166
|
end
|
167
167
|
|
168
168
|
# Returns a list of scopes that should be applied for this Reflection
|
@@ -623,6 +623,7 @@ module ActiveRecord
|
|
623
623
|
# with the current reflection's klass name.
|
624
624
|
def valid_inverse_reflection?(reflection)
|
625
625
|
reflection &&
|
626
|
+
foreign_key == reflection.foreign_key &&
|
626
627
|
klass <= reflection.active_record &&
|
627
628
|
can_find_inverse_of_automatically?(reflection)
|
628
629
|
end
|
@@ -32,9 +32,9 @@ module ActiveRecord
|
|
32
32
|
def self.references(attributes)
|
33
33
|
attributes.each_with_object([]) do |(key, value), result|
|
34
34
|
if value.is_a?(Hash)
|
35
|
-
result << key
|
35
|
+
result << Arel.sql(key)
|
36
36
|
elsif key.include?(".")
|
37
|
-
result << key.split(".").first
|
37
|
+
result << Arel.sql(key.split(".").first)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -59,7 +59,7 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def build(attribute, value, operator = nil)
|
62
|
-
value = value.id if value.
|
62
|
+
value = value.id if value.respond_to?(:id)
|
63
63
|
if operator ||= table.type(attribute.name).force_equality?(value) && :eq
|
64
64
|
bind = build_bind_attribute(attribute.name, value)
|
65
65
|
attribute.public_send(operator, bind)
|
@@ -93,14 +93,11 @@ module ActiveRecord
|
|
93
93
|
# PriceEstimate.where(estimate_of: treasure)
|
94
94
|
associated_table = table.associated_table(key)
|
95
95
|
if associated_table.polymorphic_association?
|
96
|
-
|
97
|
-
|
98
|
-
value = [value] unless value.is_a?(Array)
|
99
|
-
klass = PolymorphicArrayValue
|
100
|
-
end
|
96
|
+
value = [value] unless value.is_a?(Array)
|
97
|
+
klass = PolymorphicArrayValue
|
101
98
|
elsif associated_table.through_association?
|
102
99
|
next associated_table.predicate_builder.expand_from_hash(
|
103
|
-
associated_table.
|
100
|
+
associated_table.primary_key => value
|
104
101
|
)
|
105
102
|
end
|
106
103
|
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def queries
|
12
|
-
[associated_table.join_foreign_key => ids]
|
12
|
+
[ associated_table.join_foreign_key => ids ]
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
@@ -31,9 +31,8 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def convert_to_id(value)
|
34
|
-
|
35
|
-
|
36
|
-
value._read_attribute(primary_key)
|
34
|
+
if value.respond_to?(primary_key)
|
35
|
+
value.public_send(primary_key)
|
37
36
|
else
|
38
37
|
value
|
39
38
|
end
|
@@ -9,11 +9,13 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def queries
|
12
|
+
return [ associated_table.join_foreign_key => values ] if values.empty?
|
13
|
+
|
12
14
|
type_to_ids_mapping.map do |type, ids|
|
13
|
-
{
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
query = {}
|
16
|
+
query[associated_table.join_foreign_type] = type if type
|
17
|
+
query[associated_table.join_foreign_key] = ids
|
18
|
+
query
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -23,7 +25,7 @@ module ActiveRecord
|
|
23
25
|
def type_to_ids_mapping
|
24
26
|
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
25
27
|
values.each_with_object(default_hash) do |value, hash|
|
26
|
-
hash[klass(value)
|
28
|
+
hash[klass(value)&.polymorphic_name] << convert_to_id(value)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -46,6 +48,8 @@ module ActiveRecord
|
|
46
48
|
value._read_attribute(primary_key(value))
|
47
49
|
when Relation
|
48
50
|
value.select(primary_key(value))
|
51
|
+
else
|
52
|
+
value
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
@@ -1081,12 +1081,15 @@ module ActiveRecord
|
|
1081
1081
|
when String, Array
|
1082
1082
|
parts = [klass.sanitize_sql(rest.empty? ? opts : [opts, *rest])]
|
1083
1083
|
when Hash
|
1084
|
-
opts = opts.
|
1084
|
+
opts = opts.transform_keys do |key|
|
1085
|
+
key = key.to_s
|
1086
|
+
klass.attribute_aliases[key] || key
|
1087
|
+
end
|
1085
1088
|
references = PredicateBuilder.references(opts)
|
1086
1089
|
self.references_values |= references unless references.empty?
|
1087
1090
|
|
1088
1091
|
parts = predicate_builder.build_from_hash(opts) do |table_name|
|
1089
|
-
|
1092
|
+
lookup_table_klass_from_join_dependencies(table_name)
|
1090
1093
|
end
|
1091
1094
|
when Arel::Nodes::Node
|
1092
1095
|
parts = [opts]
|
@@ -1099,9 +1102,9 @@ module ActiveRecord
|
|
1099
1102
|
alias :build_having_clause :build_where_clause
|
1100
1103
|
|
1101
1104
|
private
|
1102
|
-
def
|
1105
|
+
def lookup_table_klass_from_join_dependencies(table_name)
|
1103
1106
|
each_join_dependencies do |join|
|
1104
|
-
return join.
|
1107
|
+
return join.base_klass if table_name == join.table_name
|
1105
1108
|
end
|
1106
1109
|
nil
|
1107
1110
|
end
|
@@ -1312,7 +1315,7 @@ module ActiveRecord
|
|
1312
1315
|
elsif field.match?(/\A\w+\.\w+\z/)
|
1313
1316
|
table, column = field.split(".")
|
1314
1317
|
predicate_builder.resolve_arel_attribute(table, column) do
|
1315
|
-
|
1318
|
+
lookup_table_klass_from_join_dependencies(table)
|
1316
1319
|
end
|
1317
1320
|
else
|
1318
1321
|
yield field
|
@@ -1505,7 +1508,7 @@ module ActiveRecord
|
|
1505
1508
|
v1 = v1.uniq
|
1506
1509
|
v2 = v2.uniq
|
1507
1510
|
end
|
1508
|
-
v1 == v2
|
1511
|
+
v1 == v2
|
1509
1512
|
end
|
1510
1513
|
end
|
1511
1514
|
end
|
@@ -69,8 +69,8 @@ module ActiveRecord
|
|
69
69
|
|
70
70
|
private
|
71
71
|
def relation_with(values)
|
72
|
-
result =
|
73
|
-
result.
|
72
|
+
result = spawn
|
73
|
+
result.instance_variable_set(:@values, values)
|
74
74
|
result
|
75
75
|
end
|
76
76
|
end
|
@@ -23,11 +23,9 @@ module ActiveRecord
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def create_table
|
26
|
-
unless table_exists?
|
27
|
-
version_options = connection.internal_string_options_for_primary_key
|
28
|
-
|
26
|
+
unless connection.table_exists?(table_name)
|
29
27
|
connection.create_table(table_name, id: false) do |t|
|
30
|
-
t.string :version, **
|
28
|
+
t.string :version, **connection.internal_string_options_for_primary_key
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
# a certain time period.
|
21
21
|
#
|
22
22
|
# You set the time period that the signed id is valid for during generation, using the instance method
|
23
|
-
#
|
23
|
+
# <tt>signed_id(expires_in: 15.minutes)</tt>. If the time has elapsed before a signed find is attempted,
|
24
24
|
# the signed id will no longer be valid, and nil is returned.
|
25
25
|
#
|
26
26
|
# It's possible to further restrict the use of a signed id with a purpose. This helps when you have a
|