-
Notifications
You must be signed in to change notification settings - Fork 6
Adds polymophic relation, trackable, to billing_usage_trackers. #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| model ||= self.class | ||
|
|
||
| send(BulletTrain::Billing::Usage.parent_association).billing_usage_trackers.current.each do |tracker| | ||
| billing_usage_trackers.current.each do |tracker| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the send(BulletTrain::Billing::Usage.parent_association) because with these changes, parent_association needs to be dynamic, but being a class var makes it tricky. Removing it makes it work for our case, but it may not be ideal for the main gem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super familiar with this gem, so I'm not entirely sure, but I think this may cause trouble for apps that are already using this gem.
To take the example from the docs imagine that someone has done this:
class Blogs::Post < ApplicationRecord
# ...
def publish!
update(published_at: Time.zone.now)
track_billing_usage(:published)
end
endBefore this change the track_billing_usage call would be equivalent to doing:
Billing::Usage::Trackers.where(team_id: self.team).current.each do |tracker|
# ...
endAnd after if would be doing:
Billing::Usage::Trackers.where(trackable_type: "Blog", trackable_id: self.id).current.each do |tracker|
# ...
endIt seems like the usage would start getting tracked in a different place and the counts would be thrown off. Do we need to figure out a way to migrate the existing records into a new place? Or is there some way to rebuild the counts from scratch after making the update?
| workspace_id = if proxy_association.owner.is_a?(Workspace) | ||
| proxy_association.owner.id | ||
| else | ||
| proxy_association.owner.workspace.id | ||
| end | ||
|
|
||
| # This will grab the most recent tracker for this usage cycle. | ||
| # If it doesn't exist, it will be created. This can happen if developers introduce new usage cycles to track by. | ||
| order(created_at: :desc).includes(:counts).find_or_create_by(duration: duration, interval: interval) | ||
| order(created_at: :desc).includes(:counts).find_or_create_by( | ||
| workspace_id: workspace_id, | ||
| duration: duration, | ||
| interval: interval | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes are specific to clickfunnels. I think once workspace_id is dropped, we can drop these changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that we want to release clickfunnels specific stuff in the gem. Most apps won't have a workspace_id and this will cause problems. Maybe we could remove this workspace_id stuff from this PR and you all could eject this file and maintain a custom version of it?
|
@swinner2 Can we get more context on the use case here? What situation required this? |
Yes, so currently, there is one parent for all limits. We needed the ability to track on a more granular level. For example, take a limit rule like a team can have blogs, but each blog can only have 10 posts. We'd need the ability to track the number of posts on a specific blog instead of the number of posts on the whole Team. Making the parent dynamic solves this. |
|
Amazing, makes total sense. Thanks for this! |
3181b2d to
15dcc7a
Compare
jagthedrummer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👋 Hey @swinner2, long time no see! I hope you're doing well.
For the most part this is looking good. My biggest questions are:
- Can we remove the Clickfunnels specific bits so that they don't break other non-Cf apps?
- How can we help people make the transition from trackers having the equivalent of
belongs_to :team(or whatever association has been configured) to havingbelongs_to :trackable, polymorphic: true. (Related question: How likely is it that someone would have configured a differentparent_associationand what all hoops would they have had to jump through to do so? I kinda seems like just changingparent_classwouldn't be sufficient since there's ateam_idcolumn on thebilling_usage_trackerstable...)
I left some specific comments/questions inline.
| workspace_id = if proxy_association.owner.is_a?(Workspace) | ||
| proxy_association.owner.id | ||
| else | ||
| proxy_association.owner.workspace.id | ||
| end | ||
|
|
||
| # This will grab the most recent tracker for this usage cycle. | ||
| # If it doesn't exist, it will be created. This can happen if developers introduce new usage cycles to track by. | ||
| order(created_at: :desc).includes(:counts).find_or_create_by(duration: duration, interval: interval) | ||
| order(created_at: :desc).includes(:counts).find_or_create_by( | ||
| workspace_id: workspace_id, | ||
| duration: duration, | ||
| interval: interval | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that we want to release clickfunnels specific stuff in the gem. Most apps won't have a workspace_id and this will cause problems. Maybe we could remove this workspace_id stuff from this PR and you all could eject this file and maintain a custom version of it?
| class AddTrackableToBillingUsageTracker < ActiveRecord::Migration[7.1] | ||
| def change | ||
| add_column :billing_usage_trackers, :trackable_id, :bigint | ||
| add_column :billing_usage_trackers, :trackable_type, :string, default: "Team" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of defaulting to "Team" should we maybe default to BulletTrain::Billing::Usage.parent_association in case someone has overridden that association?
| t.integer "count", default: 0, null: false | ||
| t.datetime "created_at", null: false | ||
| t.datetime "updated_at", null: false | ||
| t.index ["action", "name", "tracker_id"], name: "index_billing_usage_counts_on_action_and_name_and_tracker_id", unique: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There doesn't seem to be a migration for this change. Do we need one? Or should we drop this line? (I realize this is the schema for the dummy app, just wondering if downstream apps need this change or not.)
| t.bigint "team_id", null: false | ||
| t.integer "duration", null: false | ||
| t.string "interval", null: false | ||
| t.jsonb "usage", default: {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another schema change without a matching migration.
| duration { 1 } | ||
| interval { "month" } | ||
| association :team | ||
| association :trackable, factory: :team |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to somehow use BulletTrain::Billing::Usage.parent_association here in case somebody has changed the default?
| model ||= self.class | ||
|
|
||
| send(BulletTrain::Billing::Usage.parent_association).billing_usage_trackers.current.each do |tracker| | ||
| billing_usage_trackers.current.each do |tracker| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super familiar with this gem, so I'm not entirely sure, but I think this may cause trouble for apps that are already using this gem.
To take the example from the docs imagine that someone has done this:
class Blogs::Post < ApplicationRecord
# ...
def publish!
update(published_at: Time.zone.now)
track_billing_usage(:published)
end
endBefore this change the track_billing_usage call would be equivalent to doing:
Billing::Usage::Trackers.where(team_id: self.team).current.each do |tracker|
# ...
endAnd after if would be doing:
Billing::Usage::Trackers.where(trackable_type: "Blog", trackable_id: self.id).current.each do |tracker|
# ...
endIt seems like the usage would start getting tracked in a different place and the counts would be thrown off. Do we need to figure out a way to migrate the existing records into a new place? Or is there some way to rebuild the counts from scratch after making the update?
|
Another couple of questions regarding this:
Considering that someone might want a rule more like:
How would these two things be configured differently in If someone already had the "10 posts across all blogs" rule in place, would this change kind of forcibly switch them to the "each blog can have 10 posts" rule? If I'm understanding this PR correctly I think it would fundamentally change the meaning of a limit like this: basic:
prices:
# ...
limits:
posts:
have:
count: 10
enforcement: hard
upgradable: trueI think that before this change that block would mean "10 posts across all blogs" and after this change it would mean "10 posts per blog". Is that accurate? And is it what we want? Do we need a way to configure the parent association at the limit level inside |
This PR adds support for a polymorphic parent of
Billing::Usage::Tracker.