Module: SorbetRails::ModelUtils

Extended by:
T::Helpers, T::Sig
Included in:
SorbetRails::ModelPlugins::Base, ModelRbiFormatter
Defined in:
lib/sorbet-rails/model_utils.rb

Overview

typed: strict

Instance Method Summary collapse

Instance Method Details

#add_relation_query_method(root, method_name, parameters: nil, builtin_query_method: false) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/sorbet-rails/model_utils.rb', line 92

def add_relation_query_method(root, method_name, parameters: nil, builtin_query_method: false)
  # a relation querying method will be available on
  # - model (as a class method)
  # - activerecord relation
  # - asocciation collection proxy
  # - association relation
  # in case (1) and (2), it returns a Model::ActiveRecord_Relation
  # in case (3) and (4), it returns a Model::ActiveRecord_AssociationRelation

  # 'unscoped' is a special case where it always returns a ActiveRecord_Relation
  assoc_return_value = method_name == 'unscoped' ? self.model_relation_class_name : self.model_assoc_relation_class_name

  # We can put methods onto modules which are extended/included by the model
  # and relation classes which reduces the RBI footprint for an individual
  # model. However, in Rails 5 query methods that come from scopes or enums
  # get overridden in hidden-definitions so we need to explicitly define them
  # on the model and relation classes.
  if builtin_query_method
    relation_module_rbi = root.create_module(self.model_query_methods_returning_relation_module_name)
    relation_module_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
    )

    assoc_relation_module_rbi = root.create_module(self.model_query_methods_returning_assoc_relation_module_name)
    assoc_relation_module_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )
  else
    # force generating these methods because sorbet's hidden-definitions generate & override them
    model_class_rbi = root.create_class(self.model_class_name)
    model_class_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
      class_method: true,
    )

    model_relation_rbi = root.create_class(self.model_relation_class_name)
    model_relation_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
    )

    model_assoc_relation_rbi = root.create_class(self.model_assoc_relation_class_name)
    model_assoc_relation_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )

    collection_proxy_rbi = root.create_class(self.model_assoc_proxy_class_name)
    collection_proxy_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )
  end
end

#exists_class_method?(method_name) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/sorbet-rails/model_utils.rb', line 77

def exists_class_method?(method_name)
  model_class.respond_to?(method_name)
end

#exists_instance_method?(method_name) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/sorbet-rails/model_utils.rb', line 72

def exists_instance_method?(method_name)
  model_class.method_defined?(method_name)
end

#habtm_class?Boolean

Returns:

  • (Boolean)


14
15
16
17
18
# File 'lib/sorbet-rails/model_utils.rb', line 14

def habtm_class?
  # checking the class name seems to be the cleanest way to figure this out, see:
  # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb#L54
  T.must(model_class.name).start_with?('HABTM_')
end

#model_assoc_proxy_class_nameObject



31
32
33
# File 'lib/sorbet-rails/model_utils.rb', line 31

def model_assoc_proxy_class_name
  "#{model_class_name}::ActiveRecord_Associations_CollectionProxy"
end

#model_assoc_relation_class_nameObject



36
37
38
# File 'lib/sorbet-rails/model_utils.rb', line 36

def model_assoc_relation_class_name
  "#{model_class_name}::ActiveRecord_AssociationRelation"
end

#model_classObject



11
# File 'lib/sorbet-rails/model_utils.rb', line 11

def model_class; end

#model_class_nameObject



21
22
23
# File 'lib/sorbet-rails/model_utils.rb', line 21

def model_class_name
  model_class.to_s
end

#model_module_name(module_name) ⇒ Object



67
68
69
# File 'lib/sorbet-rails/model_utils.rb', line 67

def model_module_name(module_name)
  "#{model_class_name}::#{module_name}"
end

#model_query_methods_returning_assoc_relation_module_nameObject



46
47
48
# File 'lib/sorbet-rails/model_utils.rb', line 46

def model_query_methods_returning_assoc_relation_module_name
  "#{model_class_name}::QueryMethodsReturningAssociationRelation"
end

#model_query_methods_returning_relation_module_nameObject



41
42
43
# File 'lib/sorbet-rails/model_utils.rb', line 41

def model_query_methods_returning_relation_module_name
  "#{model_class_name}::QueryMethodsReturningRelation"
end

#model_relation_class_nameObject



26
27
28
# File 'lib/sorbet-rails/model_utils.rb', line 26

def model_relation_class_name
  "#{model_class_name}::ActiveRecord_Relation"
end

#model_relation_type_aliasObject



51
52
53
54
55
56
57
58
59
# File 'lib/sorbet-rails/model_utils.rb', line 51

def model_relation_type_alias
  types = [
    self.model_relation_class_name,
    self.model_assoc_proxy_class_name,
    self.model_assoc_relation_class_name
  ].join(', ')

  "T.any(#{types})"
end

#model_relation_type_class_nameObject



62
63
64
# File 'lib/sorbet-rails/model_utils.rb', line 62

def model_relation_type_class_name
  'RelationType'
end