From caf514399fd8e642af367c6d88567d6c7400083b Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 14:20:14 +0100 Subject: [PATCH 1/8] fix: add support of has_and_belongs_to_many relation --- .../utils/schema/schema_emitter.rb | 2 +- .../collection.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/schema_emitter.rb b/packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/schema_emitter.rb index dd0cdf6ff..326bda986 100644 --- a/packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/schema_emitter.rb +++ b/packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/schema_emitter.rb @@ -88,7 +88,7 @@ def serialize(schema) { data: data, - included: included.reject!(&:empty?)&.flatten, + included: included.reject!(&:empty?)&.flatten || [], meta: schema[:meta] } end diff --git a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb index 141143751..7203b02f3 100644 --- a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb +++ b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb @@ -175,6 +175,18 @@ def fetch_associations ) end end + when :has_and_belongs_to_many + add_field( + association.name.to_s, + ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new( + foreign_collection: format_model_name(association.klass.name), + origin_key: association.association_foreign_key, + origin_key_target: association.association_primary_key, + foreign_key: association.join_primary_key, + foreign_key_target: association.join_foreign_key, + through_collection: association.join_table.singularize + ) + ) end end end From b7cd8143b133daaecab4db822b92bbbc292b4f0e Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 14:27:00 +0100 Subject: [PATCH 2/8] fix: many to many keys --- .../forest_admin_datasource_active_record/collection.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb index 7203b02f3..dfb1a185b 100644 --- a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb +++ b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb @@ -180,10 +180,10 @@ def fetch_associations association.name.to_s, ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new( foreign_collection: format_model_name(association.klass.name), - origin_key: association.association_foreign_key, - origin_key_target: association.association_primary_key, - foreign_key: association.join_primary_key, - foreign_key_target: association.join_foreign_key, + origin_key: association.join_primary_key, + origin_key_target: association.join_foreign_key, + foreign_key: association.association_foreign_key, + foreign_key_target: association.association_primary_key, through_collection: association.join_table.singularize ) ) From aa738e6d54459abf7d08ffe19d1a672960aaacb7 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 16:15:28 +0100 Subject: [PATCH 3/8] fix: lint --- .rubocop.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index d4761e1fb..f1253a4ab 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-performance - rubocop-rspec @@ -329,3 +329,6 @@ Lint/InterpolationCheck: Lint/UnusedMethodArgument: Exclude: - 'packages/forest_admin_rails/config/initializers/forest_admin_error_subscriber.rb' + +Style/RedundantParentheses: + Enabled: false From 0e5abb9f660bb4d931602f2112dc734a9c3ab786 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 17:35:01 +0100 Subject: [PATCH 4/8] fix: tests on schema_emitter --- .../forest_admin_agent/utils/schema/schema_emitter_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/forest_admin_agent/spec/lib/forest_admin_agent/utils/schema/schema_emitter_spec.rb b/packages/forest_admin_agent/spec/lib/forest_admin_agent/utils/schema/schema_emitter_spec.rb index be65f9edc..2c41a2f57 100644 --- a/packages/forest_admin_agent/spec/lib/forest_admin_agent/utils/schema/schema_emitter_spec.rb +++ b/packages/forest_admin_agent/spec/lib/forest_admin_agent/utils/schema/schema_emitter_spec.rb @@ -91,7 +91,7 @@ module Schema expect(schema).to eq( { data: [], - included: nil, + included: [], meta: { liana: described_class::LIANA_NAME, liana_version: described_class::LIANA_VERSION, @@ -123,7 +123,7 @@ module Schema expect(schema).to eq( { data: [], - included: nil, + included: [], meta: json_schema[:meta] } ) From 4187ac6195ca2af9d129165a9ee2371aba170785 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 17:46:27 +0100 Subject: [PATCH 5/8] fix: ci --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b91b68e34..9ad072c7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ["3.0", "3.1", "3.2"] + ruby-version: ["3.3"] packages: - forest_admin_agent - forest_admin_datasource_active_record @@ -48,7 +48,7 @@ jobs: needs: [lint] strategy: matrix: - ruby-version: ["3.0", "3.1", "3.2"] + ruby-version: ["3.3"] packages: - forest_admin_agent - forest_admin_datasource_active_record @@ -76,7 +76,7 @@ jobs: cd - - name: Upload coverage - if: ${{ matrix.ruby-version == '3.2' }} + if: ${{ matrix.ruby-version == '3.3' }} uses: actions/upload-artifact@v4 with: name: ${{ matrix.ruby-version }}-${{ matrix.packages }} @@ -89,7 +89,7 @@ jobs: needs: [test] strategy: matrix: - ruby-version: ["3.2"] + ruby-version: ["3.3"] steps: - name: Checkout uses: actions/checkout@v4 From 61f62b0a99b95b85cda2612cca9ef2a2b7b5dbae Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 19 Feb 2025 17:52:30 +0100 Subject: [PATCH 6/8] fix: rollback ci --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ad072c7a..b91b68e34 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ["3.3"] + ruby-version: ["3.0", "3.1", "3.2"] packages: - forest_admin_agent - forest_admin_datasource_active_record @@ -48,7 +48,7 @@ jobs: needs: [lint] strategy: matrix: - ruby-version: ["3.3"] + ruby-version: ["3.0", "3.1", "3.2"] packages: - forest_admin_agent - forest_admin_datasource_active_record @@ -76,7 +76,7 @@ jobs: cd - - name: Upload coverage - if: ${{ matrix.ruby-version == '3.3' }} + if: ${{ matrix.ruby-version == '3.2' }} uses: actions/upload-artifact@v4 with: name: ${{ matrix.ruby-version }}-${{ matrix.packages }} @@ -89,7 +89,7 @@ jobs: needs: [test] strategy: matrix: - ruby-version: ["3.3"] + ruby-version: ["3.2"] steps: - name: Checkout uses: actions/checkout@v4 From 80afed1c8c145da16d2f53f6ce2813d02af7d14e Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Thu, 20 Feb 2025 10:10:56 +0100 Subject: [PATCH 7/8] test: add test fetch hatbm relation --- .../spec/dummy/app/models/company.rb | 3 +++ .../spec/dummy/app/models/user.rb | 1 + .../dummy/db/migrate/20230810095726_create_companies.rb | 8 ++++++++ .../db/migrate/20230810095727_create_companies_users.rb | 8 ++++++++ .../collection_spec.rb | 6 ++++++ 5 files changed, 26 insertions(+) create mode 100644 packages/forest_admin_datasource_active_record/spec/dummy/app/models/company.rb create mode 100644 packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095726_create_companies.rb create mode 100644 packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095727_create_companies_users.rb diff --git a/packages/forest_admin_datasource_active_record/spec/dummy/app/models/company.rb b/packages/forest_admin_datasource_active_record/spec/dummy/app/models/company.rb new file mode 100644 index 000000000..2ee075340 --- /dev/null +++ b/packages/forest_admin_datasource_active_record/spec/dummy/app/models/company.rb @@ -0,0 +1,3 @@ +class Company < ApplicationRecord + has_and_belongs_to_many :users +end diff --git a/packages/forest_admin_datasource_active_record/spec/dummy/app/models/user.rb b/packages/forest_admin_datasource_active_record/spec/dummy/app/models/user.rb index f1df24e7e..2beb4c1f7 100644 --- a/packages/forest_admin_datasource_active_record/spec/dummy/app/models/user.rb +++ b/packages/forest_admin_datasource_active_record/spec/dummy/app/models/user.rb @@ -1,6 +1,7 @@ class User < ApplicationRecord belongs_to :car has_one :address, as: :addressable + has_and_belongs_to_many :companies enum :enum_field, { draft: 0, published: 1, archived: 2, trashed: 3 } end diff --git a/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095726_create_companies.rb b/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095726_create_companies.rb new file mode 100644 index 000000000..56abf97f2 --- /dev/null +++ b/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095726_create_companies.rb @@ -0,0 +1,8 @@ +class CreateCompanies < ActiveRecord::Migration[7.0] + def change + create_table :companies do |t| + t.column :name, :string + t.timestamps + end + end +end diff --git a/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095727_create_companies_users.rb b/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095727_create_companies_users.rb new file mode 100644 index 000000000..f9987cb12 --- /dev/null +++ b/packages/forest_admin_datasource_active_record/spec/dummy/db/migrate/20230810095727_create_companies_users.rb @@ -0,0 +1,8 @@ +class CreateCompaniesUsers < ActiveRecord::Migration[7.0] + def change + create_table :companies_users, id: false do |t| + t.belongs_to :company + t.belongs_to :user + end + end +end diff --git a/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/collection_spec.rb b/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/collection_spec.rb index e02dcefc1..fd7c82283 100644 --- a/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/collection_spec.rb +++ b/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/collection_spec.rb @@ -35,6 +35,12 @@ module ForestAdminDatasourceActiveRecord expect(datasource.get_collection('User').schema[:fields].keys).not_to include('address') expect(datasource.get_collection('Address').schema[:fields].keys).not_to include('addressable') end + + it 'add has_and_belongs_to_many relation' do + collection = described_class.new(datasource, Company) + + expect(collection.schema[:fields].keys).to include('users') + end end end From 7bea7f845cfa4f28c9a3eca6adf01fdc16c1d443 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Thu, 20 Feb 2025 14:00:53 +0100 Subject: [PATCH 8/8] fix: tests --- .../collection.rb | 2 +- .../datasource.rb | 14 +++++++++++--- .../datasource_spec.rb | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb index dfb1a185b..f8fc142fa 100644 --- a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb +++ b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb @@ -184,7 +184,7 @@ def fetch_associations origin_key_target: association.join_foreign_key, foreign_key: association.association_foreign_key, foreign_key_target: association.association_primary_key, - through_collection: association.join_table.singularize + through_collection: association.join_table.classify ) ) end diff --git a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/datasource.rb b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/datasource.rb index cf0b6cad5..e7352edc6 100644 --- a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/datasource.rb +++ b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/datasource.rb @@ -78,7 +78,8 @@ def fetch_model(model) @models << model unless model.abstract_class? || @models.include?(model) || !model.table_exists? || - !primary_key?(model) + !primary_key?(model) || + model.const_defined?(:VIRTUAL_THROUGH_COLLECTION) end end @@ -101,19 +102,24 @@ def build_habtm(model) if @habtm_models.key?(model.table_name) @habtm_models[model.table_name].left_reflection = model.right_reflection # when the second model is added, we can push the HABTM model to the models list - @models << make_through_model( + through_model = make_through_model( model.table_name, [ @habtm_models[model.table_name].left_reflection, @habtm_models[model.table_name].right_reflection ] ) + + add_collection( + Collection.new(self, through_model, support_polymorphic_relations: @support_polymorphic_relations) + ) else @habtm_models[model.table_name] = model end end def make_through_model(table_name, associations) + through_model_name = table_name.classify through_model = Class.new(ActiveRecord::Base) do class << self attr_accessor :name, :table_name @@ -124,13 +130,15 @@ def self.add_association(name, options) end end - through_model.name = table_name.singularize + through_model.name = through_model_name through_model.table_name = table_name through_model.primary_key = [associations[0].foreign_key, associations[1].foreign_key] associations.each do |association| through_model.add_association(association.name, association.options) end + through_model.const_set(:VIRTUAL_THROUGH_COLLECTION, true) + through_model end end diff --git a/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/datasource_spec.rb b/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/datasource_spec.rb index ef583c150..2e496a012 100644 --- a/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/datasource_spec.rb +++ b/packages/forest_admin_datasource_active_record/spec/lib/forest_admin_datasource_active_record/datasource_spec.rb @@ -4,7 +4,7 @@ module ForestAdminDatasourceActiveRecord describe Datasource do it 'fetch all models' do datasource = described_class.new({ adapter: 'sqlite3', database: 'db/database.db' }) - expected = %w[User Order Check Category CarCheck Car Address] + expected = %w[User Order Check Category CarCheck Car Address Company CompaniesUser] expect(datasource.collections.keys).to match_array(expected) end