Comments (9)
CultOfMartians task http://cultofmartians.com/tasks/logidze-associations.html
from logidze.
I read your implementation tips on the Cult of Martians site. Do you want to somehow override ActiveRecord associations getters? Or you meant some other approach?
I think, we can patch load_target method to modify loaded items.
Also, to reduce global monkey-patching, we can patch association instances in-place, prepending some module into an instance of association in association method.
Smth like:
# this method is called on our model object, which `has_logidze`
def association(*args)
res = super
# only patch association if we request some past state
res.singleton_class.prepend Logidze::VersionedAssociation if in_the_past?
res
end
from logidze.
@ezubairov Thanks for the request!
I was thinking about this feature too, but was not sure whether it's useful or not. Now I see – it is.
So, I'll share the task on http://cultofmartians.com with some thoughts on implementation; I think, we'll find someone to handle this)
from logidze.
@palkan at last I found time to dig through this task
General question:
I read your implementation tips on the Cult of Martians site. Do you want to somehow override ActiveRecord associations getters? Or you meant some other approach?
from logidze.
@palkan hello, I think, I got it at last. Got it somewhere at least :)
It took me a while to get familiar with Rails inner association logic, I spent some time tinkering with it to just understand the clues you gave :)
Unfortunately, there is a trouble with the collection associations, particularly with the size
method. It doesn't call load_target
, if target wasn't loaded in memory already, it executes SQL count statement instead (as far as I understand it). So we can't hook into that with load_target
.
May I open the pull request, so we could discuss the actual code?
from logidze.
May I open the pull request, so we could discuss the actual code?
Yes, of course.
... particularly with the size method
We can ignore such methods at first (and add a note about it to the README).
But that's an important point, thanks for figuring it out!
from logidze.
huh, this could be handy, depending on how well it behaves. Here is what I've come up with in the mean time.
Having issues with weird log_data in tests though... like overly nested
{"c"=>
{"h"=>
[{"c"=>
# frozen_string_literal: true
#
# This is for manually creating versions using logdize's technique
#
# The automatic version on update has been disabled (but could be enabled by
# running a migration that updated the trigger).
# This is to ensure that any version, other than the first version, is
# always created by our code.
# It also means that we can use the same version for every association -- which
# simplifies relations
#
# Note that the latest version on the log_data will always be the most recent
# snapshot, and may not reflect the current state
# So, record.log_version will always be one less than the number of versions.
# E.g.: record.log_size # => 3 -- but the total versions are 3 + [current]
#
# NOTE: gem documentation: https://github.com/palkan/logidze
module Versionable
extend ActiveSupport::Concern
included do
has_logidze
# set the initial version
# after_create :save_version!
# - this happens via SQL TRIGGER
#
# increment version
# before_save :save_version!
# - this is not automatic, because we need to
# have a consistent version across relationships
# Class Methods
class << self
# for retreiving a relationship of this (whatever includes this module)
# requiring each member to match the provided version number or
# datetime of the version
#
# @param [Number] version
# @param [Time] time
def at(version: nil, time: nil)
# TODO: find a more efficient way to do this
all.map do |current|
time ? current.at!(time) : current.at_version!(version)
end
end
private
# Iterate over the associations, and add a method that will retreive
# the relationship at the same version as the calling object.
# That way we don't need to manually carry the version through our
# relation call chain.
#
# More information on reflections
# http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html#method-i-reflections
def build_versioned_reflections!
reflections.each do |association_name, reflection|
# is this a versioned reflection?
next unless reflection.klass.has_attribute?(:log_data)
define_method("#{association_name}_at_same_version") do
send(association_name).at(time: time_of_version)
end
end
end
end
# ...Metaprogramming... Wooosh
build_versioned_reflections!
end
# @return [NilClass|Time]
def time_of_version
ts = log_data&.find_by_version(version)&.data&.fetch('ts')
Time.at(ts) if ts
end
def save_version!
save_version
reload
end
# For saving logdize historical versions manually.
# Be sure that logdize has logging turned off globally
#
# TODO: have configurable parameter exclusions, such as draft_id
def save_version
return false unless has_attribute?(:log_data)
# return false unless log_data.present?
klass = self.class
klass.connection.execute(%(
SELECT make_snapshot(#{id}, '#{klass.table_name}');
))
end
# Slightly shorter than log_version, and won't error if there isn't (yet) log_data.
# log_data is only populated on save, before executing the insert or update statement
# on the db side
def version
log_data ? log_version : 0
end
end
from logidze.
@palkan what we are going to do with this issue?
from logidze.
@ezubairov hello!
Today PR, addressing this issue, was merged, you can read about it in the wiki page
from logidze.
Related Issues (20)
- #at(time: <?>) returning nil HOT 8
- Responsibility tracking integration for console sessions HOT 2
- Add Logidze.with_responsible! (block-less version)
- Logidze with Ruby 3.0 is throwing argument errors. HOT 2
- `rails destroy logidze:model MyModel` does not delete migration file HOT 2
- Activerecord table_name_prefix or table_name_suffix are not honored HOT 3
- Tracking changes on JSONB column error
- How to list all versions of a record? HOT 4
- Association versioning with ignore_log_data and at(version: ) doesn't return expected results HOT 5
- Partition-friendly logging (triggers) HOT 3
- JSONB column and switch_to! with append: true HOT 2
- PG::UndefinedFunction: ERROR: function hstore(model_name) does not exist HOT 1
- Meta per request HOT 1
- Logidze.ignore_log_data_by_default causing db:migrate errors HOT 2
- Responsible from different sources HOT 3
- Associations versioning - accessing versions with `at(version: #)` HOT 2
- How to tell logidze about a new column HOT 8
- GlobalID support for metadata
- `responsible_id` is not updated on relation with `touch: true` HOT 6
- reload_log_data doesn't work when used with acts_as_paranoid and deleted records HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from logidze.