Skip to content

Improve the Version Proof of the Gem#43

Merged
azeveco merged 18 commits intodevfrom
version_proof
May 27, 2025
Merged

Improve the Version Proof of the Gem#43
azeveco merged 18 commits intodevfrom
version_proof

Conversation

@azeveco
Copy link
Owner

@azeveco azeveco commented May 22, 2025

Context

There were still a few problems between versions, like:

  • Inheritance of the models
  • Loading models based on Rails version
  • Building a feature's identifier
  • insert_all of the BulkToggler
  • Building tracking analytics data
  • Writing the with_features scope from the lib/togglefy/assignable.rb with SQL

Resolution

Inheritance of the models && Loading models based on Rails version

There were still a few inheritance problems inside the Togglefy::Feature and the Togglefy::FeatureAssignment models. Also, there were in-model conditional validations to choose the best approach of a few things, which may cause performance problems.

For this, we've changed it how the models load, by requiring a specific model based on the Rails version only once, during the initialize of the server:

if Rails::VERSION::MAJOR >= 7
require_relative "#{ROOT_PATH}/lib/models/rails_7/feature"
elsif Rails::VERSION::MAJOR >= 5
require_relative "#{ROOT_PATH}/lib/models/rails_5/feature"
else
require_relative "#{ROOT_PATH}/lib/models/rails_legacy/feature"
end

The above example applies also to the Togglefy::FeatureAssignments.

Thanks to that, we've stopped doing in-model conditional validations.

Building a feature's identifier

Older Ruby versions did not allow a keyword argument separator from the .parameterize method.

Because of that, we've changed to parameterize without separator keyword argument and gsub to change the - to _.

insert_all of the BulkToggler

Before Rails 6, there were no insert_all method inside ActiveRecord. So, because of that, we've implemented a insert_all that will only be used when the Rails version is lower than 6.

# Build values to send to custom insert_all method for Rails versions below 6
#
# @param rows [Array<Hash>] The rows to insert.
def insert_all_flow(rows)
columns = rows.first.keys
values = rows.map do |row|
"(#{columns.map do |col|
ActiveRecord::Base.connection.quote(row[col])
end.join(", ")}, #{ActiveRecord::Base.sanitize(Time.zone.now)}, #{ActiveRecord::Base.sanitize(Time.zone.now)})"
end
insert_all(columns, values)
end
# Implements the insert_all method for Rails versions below 6.
#
# @param columns [Array] The columns to insert.
# @param values [Array] The values of the columns to insert.
def insert_all(columns, values)
sql = <<-SQL.squish
INSERT INTO togglefy_feature_assignments (#{columns.push(:created_at, :updated_at).join(", ")})
VALUES #{values.join(", ")}
SQL
ActiveRecord::Base.connection.execute(sql)
end

This adds an inline conditional to check the Rails version, but since the bulk enable isn't an operation that's done a frequently, there's no need to improve it like we did with the models. There we had to do this because many checks were calling the models.

Building tracking analytics data

The yet unreleased analytics feature was using a filter_map method to build the analytics/tracking data of a feature.

That's a problem because this method was only introduced in Ruby 2.7 and we say we support Ruby 2.4.10. So we changed that to a simpler map.

Writing the with_features scope from the lib/togglefy/assignable.rb with SQL

The with_features scope was having a problem with Rails 4.2.8. It was losing context/alias of the join with the feature_assignments, so when entering the where clause wasn't working because it could not find the table feature_assignments.

Well, it wasn't able to find it because it didn't exist. It's supposed to be togglefy_feature_assignments.

Because of that, we've decided to write the join with SQL to force the alias and make sure it will remember it.

scope :with_features, lambda { |feature_ids|
joins("INNER JOIN togglefy_feature_assignments AS feature_assignments
ON feature_assignments.assignable_id = #{table_name}.id AND
feature_assignments.assignable_type = '#{name}'")
.where(feature_assignments: {
feature_id: feature_ids
})
.distinct
}

Impacted processes/locations

  • Togglefy::Feature
  • Togglefy::FeatureAssignment
  • Togglefy::ScopedBulkWrapper && BulkToggler
  • Analytics
  • Assignable

References

#45

@azeveco azeveco changed the title Version proof Improve the Version Proof of the Gem May 27, 2025
@azeveco azeveco marked this pull request as ready for review May 27, 2025 01:36
@azeveco azeveco linked an issue May 27, 2025 that may be closed by this pull request
@azeveco azeveco self-assigned this May 27, 2025
@azeveco azeveco added enhancement New feature or request bug Something isn't working labels May 27, 2025
@azeveco azeveco merged commit 621e299 into dev May 27, 2025
2 checks passed
@azeveco azeveco deleted the version_proof branch May 27, 2025 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improvements on Ruby/Rails Version Proof

1 participant