Skip to content

Commit 787526e

Browse files
committed
fix(activerecord): refine create/create! RBS signatures and update tests
- Allow passing a block to `create` / `create!` . - Add overloads for `attributes` as an Array of hashes and array return types.
1 parent 3099a93 commit 787526e

8 files changed

Lines changed: 103 additions & 70 deletions

File tree

gems/activerecord/7.2/_test/activerecord-7.2.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,18 @@ class Article < ApplicationRecord
9191
User.order(id: :asc).reorder(id: :desc)
9292

9393
User.all.table_name
94+
95+
user = User.create(name: 'James')
96+
user.articles
97+
User.create(name: 'James') { |user| user.articles }
98+
users = User.create([{name: 'James'}, {name: 'John'}])
99+
users.first.articles
100+
User.create([{name: 'James'}, {name: 'John'}]) { |user| user.articles }
101+
102+
user = User.create!(name: 'James')
103+
user.articles
104+
User.create!(name: 'James') { |user| user.articles }
105+
users = User.create!([{name: 'James'}, {name: 'John'}])
106+
users.first.articles
107+
User.create!([{name: 'James'}, {name: 'John'}]) { |user| user.articles }
94108
end

gems/activerecord/7.2/activerecord-7.2.rbs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,44 @@ module ActiveRecord
156156

157157
module Persistence
158158
def previously_persisted?: () -> bool
159+
160+
module ClassMethods
161+
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
162+
# The resulting object is returned whether the object was saved successfully to the database or not.
163+
#
164+
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
165+
# attributes on the objects that are to be created.
166+
#
167+
# ==== Examples
168+
# # Create a single new object
169+
# User.create(first_name: 'Jamie')
170+
#
171+
# # Create an Array of new objects
172+
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
173+
#
174+
# # Create a single object and pass it into a block to set other attributes.
175+
# User.create(first_name: 'Jamie') do |u|
176+
# u.is_admin = false
177+
# end
178+
#
179+
# # Creating an Array of new objects using a block, where the block is executed for each object:
180+
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
181+
# u.is_admin = false
182+
# end
183+
def create: (Array[untyped] attributes) ?{ (instance) -> void } -> Array[instance]
184+
| (?untyped? attributes) ?{ (instance) -> void } -> instance
185+
186+
# Creates an object (or multiple objects) and saves it to the database,
187+
# if validations pass. Raises a RecordInvalid error if validations fail,
188+
# unlike Base#create.
189+
#
190+
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
191+
# These describe which attributes to be created on the object, or
192+
# multiple objects when given an Array of Hashes.
193+
def create!: (Array[untyped] attributes) ?{ (instance) -> void } -> Array[instance]
194+
| (?untyped? attributes) ?{ (instance) -> void } -> instance
195+
196+
end
159197
end
160198

161199
class InsertAll

gems/activerecord/7.2/activerecord-generated.rbs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16121,39 +16121,6 @@ module ActiveRecord
1612116121
extend ActiveSupport::Concern
1612216122

1612316123
module ClassMethods
16124-
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
16125-
# The resulting object is returned whether the object was saved successfully to the database or not.
16126-
#
16127-
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
16128-
# attributes on the objects that are to be created.
16129-
#
16130-
# ==== Examples
16131-
# # Create a single new object
16132-
# User.create(first_name: 'Jamie')
16133-
#
16134-
# # Create an Array of new objects
16135-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
16136-
#
16137-
# # Create a single object and pass it into a block to set other attributes.
16138-
# User.create(first_name: 'Jamie') do |u|
16139-
# u.is_admin = false
16140-
# end
16141-
#
16142-
# # Creating an Array of new objects using a block, where the block is executed for each object:
16143-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
16144-
# u.is_admin = false
16145-
# end
16146-
def create: (?untyped? attributes) ?{ () -> untyped } -> untyped
16147-
16148-
# Creates an object (or multiple objects) and saves it to the database,
16149-
# if validations pass. Raises a RecordInvalid error if validations fail,
16150-
# unlike Base#create.
16151-
#
16152-
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
16153-
# These describe which attributes to be created on the object, or
16154-
# multiple objects when given an Array of Hashes.
16155-
def create!: (?untyped? attributes) ?{ () -> untyped } -> untyped
16156-
1615716124
# Given an attributes hash, +instantiate+ returns a new instance of
1615816125
# the appropriate class. Accepts only keys as strings.
1615916126
#

gems/activerecord/7.2/activerecord.rbs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ module ActiveRecord
4949
def self.has_one: (Symbol, ?untyped, **untyped) -> void
5050
def self.has_and_belongs_to_many: (untyped name, ?untyped? scope, **untyped options) ?{ () -> untyped } -> untyped
5151
def self.transaction: [T] (?requires_new: boolish, ?isolation: (:read_uncommitted | :read_committed | :repeatable_read | :serializable)?, ?joinable: boolish) { () -> T } -> T
52-
def self.create: (**untyped) -> instance
53-
def self.create!: (**untyped) -> instance
5452
def self.validate: (*untyped, ?if: conditions[instance], ?unless: conditions[instance], **untyped) -> void
5553
def self.validates: (*untyped, ?if: conditions[instance], ?unless: conditions[instance], **untyped) -> void
5654

gems/activerecord/8.0/_test/activerecord-8.0.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,18 @@ class Article < ApplicationRecord
9191
User.order(id: :asc).reorder(id: :desc)
9292

9393
User.all.table_name
94+
95+
user = User.create(name: 'James')
96+
user.articles
97+
User.create(name: 'James') { |user| user.articles }
98+
users = User.create([{name: 'James'}, {name: 'John'}])
99+
users.first.articles
100+
User.create([{name: 'James'}, {name: 'John'}]) { |user| user.articles }
101+
102+
user = User.create!(name: 'James')
103+
user.articles
104+
User.create!(name: 'James') { |user| user.articles }
105+
users = User.create!([{name: 'James'}, {name: 'John'}])
106+
users.first.articles
107+
User.create!([{name: 'James'}, {name: 'John'}]) { |user| user.articles }
94108
end

gems/activerecord/8.0/activerecord-8.0.rbs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,43 @@ module ActiveRecord
156156

157157
module Persistence
158158
def previously_persisted?: () -> bool
159+
160+
module ClassMethods
161+
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
162+
# The resulting object is returned whether the object was saved successfully to the database or not.
163+
#
164+
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
165+
# attributes on the objects that are to be created.
166+
#
167+
# ==== Examples
168+
# # Create a single new object
169+
# User.create(first_name: 'Jamie')
170+
#
171+
# # Create an Array of new objects
172+
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
173+
#
174+
# # Create a single object and pass it into a block to set other attributes.
175+
# User.create(first_name: 'Jamie') do |u|
176+
# u.is_admin = false
177+
# end
178+
#
179+
# # Creating an Array of new objects using a block, where the block is executed for each object:
180+
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
181+
# u.is_admin = false
182+
# end
183+
def create: (Array[untyped] attributes) ?{ (instance) -> void } -> Array[instance]
184+
| (?untyped? attributes) ?{ (instance) -> void } -> instance
185+
186+
# Creates an object (or multiple objects) and saves it to the database,
187+
# if validations pass. Raises a RecordInvalid error if validations fail,
188+
# unlike Base#create.
189+
#
190+
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
191+
# These describe which attributes to be created on the object, or
192+
# multiple objects when given an Array of Hashes.
193+
def create!: (Array[untyped] attributes) ?{ (instance) -> void } -> Array[instance]
194+
| (?untyped? attributes) ?{ (instance) -> void } -> instance
195+
end
159196
end
160197

161198
class InsertAll

gems/activerecord/8.0/activerecord-generated.rbs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16121,39 +16121,6 @@ module ActiveRecord
1612116121
extend ActiveSupport::Concern
1612216122

1612316123
module ClassMethods
16124-
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
16125-
# The resulting object is returned whether the object was saved successfully to the database or not.
16126-
#
16127-
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
16128-
# attributes on the objects that are to be created.
16129-
#
16130-
# ==== Examples
16131-
# # Create a single new object
16132-
# User.create(first_name: 'Jamie')
16133-
#
16134-
# # Create an Array of new objects
16135-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
16136-
#
16137-
# # Create a single object and pass it into a block to set other attributes.
16138-
# User.create(first_name: 'Jamie') do |u|
16139-
# u.is_admin = false
16140-
# end
16141-
#
16142-
# # Creating an Array of new objects using a block, where the block is executed for each object:
16143-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
16144-
# u.is_admin = false
16145-
# end
16146-
def create: (?untyped? attributes) ?{ () -> untyped } -> untyped
16147-
16148-
# Creates an object (or multiple objects) and saves it to the database,
16149-
# if validations pass. Raises a RecordInvalid error if validations fail,
16150-
# unlike Base#create.
16151-
#
16152-
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
16153-
# These describe which attributes to be created on the object, or
16154-
# multiple objects when given an Array of Hashes.
16155-
def create!: (?untyped? attributes) ?{ () -> untyped } -> untyped
16156-
1615716124
# Given an attributes hash, +instantiate+ returns a new instance of
1615816125
# the appropriate class. Accepts only keys as strings.
1615916126
#

gems/activerecord/8.0/activerecord.rbs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ module ActiveRecord
4949
def self.has_one: (Symbol, ?untyped, **untyped) -> void
5050
def self.has_and_belongs_to_many: (untyped name, ?untyped? scope, **untyped options) ?{ () -> untyped } -> untyped
5151
def self.transaction: [T] (?requires_new: boolish, ?isolation: (:read_uncommitted | :read_committed | :repeatable_read | :serializable)?, ?joinable: boolish) { () -> T } -> T
52-
def self.create: (**untyped) -> instance
53-
def self.create!: (**untyped) -> instance
5452
def self.validate: (*untyped, ?if: conditions[instance], ?unless: conditions[instance], **untyped) -> void
5553
def self.validates: (*untyped, ?if: conditions[instance], ?unless: conditions[instance], **untyped) -> void
5654

0 commit comments

Comments
 (0)