Class: Kithe::Model
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Kithe::Model
- Includes:
- AttrJson::NestedAttributes, AttrJson::Record, AttrJson::Record::Dirty, Indexable, StiPreload
- Defined in:
- app/models/kithe/model.rb
Direct Known Subclasses
Class Method Summary collapse
-
.kithe_earlier_after_commit(*args, &block) ⇒ Object
Insert an after_commit hook that will run BEFORE any existing after_commit hooks, regardless of Rails version and run_after_transaction_callbacks_in_order_defined configuration.
Instance Method Summary collapse
-
#friendlier_id(*_) ⇒ Object
Due to rails bug, we don’t immediately have the database-provided value after create.
-
#initialize(*_) ⇒ Model
constructor
A new instance of Model.
-
#leaf_representative ⇒ Object
insist that leaf_representative is an Asset, otherwise return nil.
-
#set_leaf_representative ⇒ Object
if a representative is set, set leaf_representative by following the tree with an efficient recursive CTE to find proper value.
-
#to_param ⇒ Object
We want friendlier_id to be in URLs, not id.
Methods included from Indexable
auto_callbacks?, index_with, #update_index
Constructor Details
Class Method Details
.kithe_earlier_after_commit(*args, &block) ⇒ Object
Insert an after_commit hook that will run BEFORE any existing after_commit hooks, regardless of Rails version and run_after_transaction_callbacks_in_order_defined configuration.
Sometimes you need to insert an after_commit hook that goes BEFORE shrine’s after_commit callbacks for promotion in activerecord after_commit
In Rails prior to 7.1, that happens automatically just by adding an after_commit. But Rails 7.1 by default changes the order of after_commit AND removes the ability to alter it with prepend! github.com/rails/rails/issues/50118
We add this method, that will do the right thing – making sure the new hook we are adding is run BEFORE any existing ones – in both Rails < 7.1 and Rails 7.1 with run_after_transaction_callbacks_in_order_defined
188 189 190 191 192 193 194 195 |
# File 'app/models/kithe/model.rb', line 188 def self.kithe_earlier_after_commit(*args, &block) # confusingly in this state, we need prepend FALSE to have this new callback be registered to go # FIRST. And this actually is correct and works whether or not run_after_transaction_callbacks_in_order_defined # Very confusing, we test thorougly. (args, {prepend: false}) set_callback(:commit, :after, *args, &block) end |
Instance Method Details
#friendlier_id(*_) ⇒ Object
Due to rails bug, we don’t immediately have the database-provided value after create. :( If we ask for it and it’s empty, go to the db to get it github.com/rails/rails/issues/21627
95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/models/kithe/model.rb', line 95 def friendlier_id(*_) in_memory = super if !in_memory && persisted? && !@friendlier_id_retrieved in_memory = self.class.where(id: id).limit(1).pluck(:friendlier_id).first write_attribute(:friendlier_id, in_memory) clear_attribute_change(:friendlier_id) # just to avoid doing it multiple times if it's still unset in db for some reason @friendlier_id_retrieved = true end in_memory end |
#leaf_representative ⇒ Object
insist that leaf_representative is an Asset, otherwise return nil. nil means there is no asset leaf, and lets caller rely on leaf being an asset.
112 113 114 115 |
# File 'app/models/kithe/model.rb', line 112 def leaf_representative leaf = super leaf.kind_of?(Kithe::Asset) ? leaf : nil end |
#set_leaf_representative ⇒ Object
if a representative is set, set leaf_representative by following the tree with an efficient recursive CTE to find proper value.
Normally this is called for you in callbacks, and you don’t need to call manually. But if things get out of sync, you can.
work.set_leaf_representative
work.save!
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 155 156 157 158 159 160 161 |
# File 'app/models/kithe/model.rb', line 125 def set_leaf_representative if self.kind_of?(Kithe::Asset) # not applicable self.leaf_representative_id = nil end # a postgres recursive CTE to find the ultimate leaf through # a possible chain of works, guarding against cycles. # https://www.postgresql.org/docs/9.1/queries-with.html recursive_cte = <<~EOS WITH RECURSIVE find_terminal(id, link) AS ( SELECT m.id, m.representative_id FROM kithe_models m WHERE m.id = $1 UNION SELECT m.id, m.representative_id FROM kithe_models m, find_terminal ft WHERE m.id = ft.link ) SELECT id FROM find_terminal WHERE link IS NULL LIMIT 1; EOS # trying to use a prepared statement, hoping it means performance advantage, # this is super undocumented bind = ActiveRecord::Relation::QueryAttribute.new("m.id", self.representative_id, ActiveRecord::Type::Value.new) result = self.class.connection.select_all( recursive_cte, "set_leaf_representative", [bind], preparable: true ).first.try(:dig, "id") self.leaf_representative_id = result end |
#to_param ⇒ Object
We want friendlier_id to be in URLs, not id
88 89 90 |
# File 'app/models/kithe/model.rb', line 88 def to_param friendlier_id end |