Class: Tapioca::Dsl::Compilers::ActiveRecordColumns
- Inherits:
-
Tapioca::Dsl::Compiler
- Object
- Tapioca::Dsl::Compiler
- Tapioca::Dsl::Compilers::ActiveRecordColumns
- Includes:
- Helpers::ActiveRecordConstantsHelper
- Defined in:
- lib/tapioca/dsl/compilers/active_record_columns.rb
Overview
Tapioca::Dsl::Compilers::ActiveRecordColumns refines RBI files for subclasses of
ActiveRecord::Base.
This compiler is only responsible for defining the attribute methods that would be
created for columns and virtual attributes that are defined in the Active Record
model.
This compiler accepts a ActiveRecordColumnTypes option that can be used to specify
how the types of the column related methods should be generated. The option can be one of the following:
persisted(default): The methods will be generated with the type that matches the actual database column type as the return type. This means that if the column is a string, the method return type will beString, but if the column is also nullable, then the return type will beT.nilable(String). This mode basically treats each model as if it was a valid and persisted model. Note that this makes typing Active Record models easier, but does not match the behaviour of non-persisted or invalid models, which can have all kinds of non-sensical values in their column attributes.nilable: All column methods will be generated withT.nilablereturn types. This is strictly the most correct way to type the methods, but it can make working with the models more cumbersome, as you will have to handle thenilcases explicitly usingT.mustor the safe navigation operator&., even for valid persisted models.untyped: The methods will be generated withT.untypedreturn types. This mode is practical if you are not ready to start typing your models strictly yet, but still want to generate RBI files for them.
For example, with the following model class:
class Post < ActiveRecord::Base
end
and the following database schema:
# db/schema.rb
create_table :posts do |t|
t.string :title, null: false
t.string :body
t.boolean :published
t.timestamps
end
this compiler will, by default, produce the following methods in the RBI file
post.rbi:
# post.rbi
# typed: true
class Post
include GeneratedAttributeMethods
module GeneratedAttributeMethods
sig { returns(T.nilable(::String)) }
def body; end
sig { params(value: T.nilable(::String)).returns(T.nilable(::String)) }
def body=; end
sig { returns(T::Boolean) }
def body?; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def created_at; end
sig { params(value: ::ActiveSupport::TimeWithZone).returns(::ActiveSupport::TimeWithZone) }
def created_at=; end
sig { returns(T::Boolean) }
def created_at?; end
sig { returns(T.nilable(T::Boolean)) }
def published; end
sig { params(value: T::Boolean).returns(T::Boolean) }
def published=; end
sig { returns(T::Boolean) }
def published?; end
sig { returns(::String) }
def title; end
sig { params(value: ::String).returns(::String) }
def title=(value); end
sig { returns(T::Boolean) }
def title?; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def updated_at; end
sig { params(value: ::ActiveSupport::TimeWithZone).returns(::ActiveSupport::TimeWithZone) }
def updated_at=; end
sig { returns(T::Boolean) }
def updated_at?; end
## Also the methods added by https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html
## Also the methods added by https://api.rubyonrails.org/classes/ActiveModel/Dirty.html
## Also the methods added by https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html
end
end
However, if ActiveRecordColumnTypes is set to nilable, the title method will be generated as:
sig { returns(T.nilable(::String)) }
def title; end
and if the option is set to untyped, the title method will be generated as:
sig { returns(T.untyped) }
def title; end
: [ConstantType = singleton(ActiveRecord::Base)]
Constant Summary
Constants included from Helpers::ActiveRecordConstantsHelper
Helpers::ActiveRecordConstantsHelper::AssociationMethodsModuleName, Helpers::ActiveRecordConstantsHelper::AssociationRelationClassName, Helpers::ActiveRecordConstantsHelper::AssociationRelationGroupChainClassName, Helpers::ActiveRecordConstantsHelper::AssociationRelationMethodsModuleName, Helpers::ActiveRecordConstantsHelper::AssociationRelationWhereChainClassName, Helpers::ActiveRecordConstantsHelper::AssociationsCollectionProxyClassName, Helpers::ActiveRecordConstantsHelper::AttributeMethodsModuleName, Helpers::ActiveRecordConstantsHelper::CommonRelationMethodsModuleName, Helpers::ActiveRecordConstantsHelper::DelegatedTypesModuleName, Helpers::ActiveRecordConstantsHelper::ReflectionType, Helpers::ActiveRecordConstantsHelper::RelationClassName, Helpers::ActiveRecordConstantsHelper::RelationGroupChainClassName, Helpers::ActiveRecordConstantsHelper::RelationMethodsModuleName, Helpers::ActiveRecordConstantsHelper::RelationWhereChainClassName, Helpers::ActiveRecordConstantsHelper::SecureTokensModuleName, Helpers::ActiveRecordConstantsHelper::StoredAttributesModuleName
Constants included from Runtime::Reflection
Runtime::Reflection::ANCESTORS_METHOD, Runtime::Reflection::CLASS_METHOD, Runtime::Reflection::CONSTANTS_METHOD, Runtime::Reflection::EQUAL_METHOD, Runtime::Reflection::METHOD_METHOD, Runtime::Reflection::NAME_METHOD, Runtime::Reflection::OBJECT_ID_METHOD, Runtime::Reflection::PRIVATE_INSTANCE_METHODS_METHOD, Runtime::Reflection::PROTECTED_INSTANCE_METHODS_METHOD, Runtime::Reflection::PUBLIC_INSTANCE_METHODS_METHOD, Runtime::Reflection::REQUIRED_FROM_LABELS, Runtime::Reflection::SINGLETON_CLASS_METHOD, Runtime::Reflection::SUPERCLASS_METHOD, Runtime::Reflection::SignatureBlockError, Runtime::Reflection::UNDEFINED_CONSTANT
Constants included from RBIHelper
RBIHelper::TYPE_PARAMETER_MATCHER
Constants included from SorbetHelper
SorbetHelper::FEATURE_REQUIREMENTS, SorbetHelper::SORBET_BIN, SorbetHelper::SORBET_EXE_PATH_ENV_VAR, SorbetHelper::SORBET_GEM_SPEC, SorbetHelper::SORBET_PAYLOAD_URL, SorbetHelper::SPOOM_CONTEXT
Instance Attribute Summary
Attributes inherited from Tapioca::Dsl::Compiler
Class Method Summary collapse
-
.gather_constants ⇒ Object
: -> Enumerable[Module[top]].
Instance Method Summary collapse
-
#decorate ⇒ Object
: -> void.
Methods inherited from Tapioca::Dsl::Compiler
#add_error, #compiler_enabled?, handles?, #initialize, processable_constants, requested_constants=, reset_state
Methods included from Runtime::Reflection
#abstract_type_of, #ancestors_of, #are_equal?, #attached_class_of, #class_of, #const_source_location, #constant_defined?, #constantize, #constants_of, #descendants_of, #file_candidates_for, #final_module?, #inherited_ancestors_of, #method_of, #name_of, #name_of_type, #object_id_of, #private_instance_methods_of, #protected_instance_methods_of, #public_instance_methods_of, #qualified_name_of, #resolve_loc, #sealed_module?, #signature_of, #signature_of!, #singleton_class_of, #superclass_of
Methods included from RBIHelper
#anonymous_parameter_name?, #as_nilable_type, #as_non_nilable_type, #create_block_param, #create_kw_opt_param, #create_kw_param, #create_kw_rest_param, #create_opt_param, #create_param, #create_rest_param, #create_typed_param, #extract_type_parameters, #sanitize_signature_types, serialize_type_variable, #valid_method_name?, #valid_parameter_name?
Methods included from SorbetHelper
#sorbet, #sorbet_path, #sorbet_supports?, #sorbet_syntax_check!
Constructor Details
This class inherits a constructor from Tapioca::Dsl::Compiler
Class Method Details
.gather_constants ⇒ Object
: -> Enumerable[Module[top]]
167 168 169 |
# File 'lib/tapioca/dsl/compilers/active_record_columns.rb', line 167 def gather_constants descendants_of(::ActiveRecord::Base).reject(&:abstract_class?) end |
Instance Method Details
#decorate ⇒ Object
: -> void
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 155 156 157 158 159 160 161 162 |
# File 'lib/tapioca/dsl/compilers/active_record_columns.rb', line 129 def decorate return unless constant.table_exists? # We need to call this to ensure that some attribute aliases are defined, e.g. # `id_value` as an alias for `id`. # I think this is a regression on Rails 7.1, but we are where we are. constant.define_attribute_methods root.create_path(constant) do |model| model.create_module(AttributeMethodsModuleName) do |mod| (constant.attribute_names + ["id"]).uniq.each do |attribute_name| add_methods_for_attribute(mod, attribute_name) end constant.attribute_aliases.each do |attribute_name, column_name| attribute_name = attribute_name.to_s column_name = column_name.to_s patterns = if constant.respond_to?(:attribute_method_patterns) # https://github.com/rails/rails/pull/44367 constant.attribute_method_patterns else T.unsafe(constant).attribute_method_matchers end new_method_names = patterns.map { |m| m.method_name(attribute_name) } old_method_names = patterns.map { |m| m.method_name(column_name) } methods_to_add = new_method_names - old_method_names add_methods_for_attribute(mod, attribute_name, column_name, methods_to_add) end end model.create_include(AttributeMethodsModuleName) end end |