diff --git a/packages/forest_admin_agent/lib/forest_admin_agent/serializer/forest_serializer_override.rb b/packages/forest_admin_agent/lib/forest_admin_agent/serializer/forest_serializer_override.rb index 3d40fc99e..cac431839 100644 --- a/packages/forest_admin_agent/lib/forest_admin_agent/serializer/forest_serializer_override.rb +++ b/packages/forest_admin_agent/lib/forest_admin_agent/serializer/forest_serializer_override.rb @@ -60,7 +60,10 @@ def self.find_recursive_relationships(root_object, root_inclusion_tree, results, objects.each do |obj| relation = ForestAdminAgent::Facades::Container.datasource.get_collection(options[:class_name]).schema[:fields][attribute_name] relation_class_name = ForestAdminAgent::Facades::Container.datasource.get_collection(relation.foreign_collection).name - obj_serializer = JSONAPI::Serializer.find_serializer(obj, options) + option_relation = options.clone + option_relation[:class_name] = relation_class_name + obj_serializer = JSONAPI::Serializer.find_serializer(obj, option_relation) + # Use keys of ['posts', '1'] for the results to enforce uniqueness. # Spec: A compound document MUST NOT include more than one resource object for each # type and id pair. @@ -200,7 +203,6 @@ def self.serialize(objects, options = {}) # of the internal special merging logic. find_recursive_relationships(obj, inclusion_tree, relationship_data, passthrough_options) end - result['included'] = relationship_data.map do |_, data| included_passthrough_options = {} included_passthrough_options[:base_url] = passthrough_options[:base_url] 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 2b5b8e852..7092b2a3a 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 @@ -47,11 +47,10 @@ def delete(_caller, filter) def fetch_fields @model.columns_hash.each do |column_name, column| - # TODO: check is not sti column field = ForestAdminDatasourceToolkit::Schema::ColumnSchema.new( column_type: get_column_type(@model, column), filter_operators: operators_for_column_type(get_column_type(@model, column)), - is_primary_key: column_name == @model.primary_key, + is_primary_key: column_name == @model.primary_key || @model.primary_key.include?(column_name), is_read_only: false, is_sortable: true, default_value: column.default, 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 f0e39d99a..dc5d19f81 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 @@ -5,6 +5,7 @@ class Datasource < ForestAdminDatasourceToolkit::Datasource def initialize(db_config = {}) super() @models = [] + @habtm_models = {} init_orm(db_config) generate end @@ -19,11 +20,52 @@ def generate end def fetch_model(model) - @models << model unless model.abstract_class? || @models.include?(model) || !model.table_exists? + if model.name.start_with?('HABTM_') + build_habtm(model) + else + @models << model unless model.abstract_class? || @models.include?(model) || !model.table_exists? + end end def init_orm(db_config) ActiveRecord::Base.establish_connection(db_config) end + + 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( + model.table_name, + [ + @habtm_models[model.table_name].left_reflection, + @habtm_models[model.table_name].right_reflection + ] + ) + else + @habtm_models[model.table_name] = model + end + end + + def make_through_model(table_name, associations) + through_model = Class.new(ActiveRecord::Base) do + class << self + attr_accessor :name, :table_name + end + + def self.add_association(name, options) + belongs_to name, required: false, **options + end + end + + through_model.name = table_name.singularize + 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 + end end end diff --git a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/utils/query.rb b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/utils/query.rb index 3ef71e225..3ef097fa1 100644 --- a/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/utils/query.rb +++ b/packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/utils/query.rb @@ -107,9 +107,7 @@ def build_select def apply_select unless @projection.nil? @query = @query.select(@select.join(', ')) - @query = @query.eager_load(@projection.relations.keys.map(&:to_sym)) - # TODO: replace eager_load by joins because eager_load select ALL columns of relation - # @query = @query.joins(@projection.relations.keys.map(&:to_sym)) + @query = @query.joins(@projection.relations.keys.map(&:to_sym)) end @query diff --git a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/datasource_customizer.rb b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/datasource_customizer.rb index bc4d80c73..11cd9cbe4 100644 --- a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/datasource_customizer.rb +++ b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/datasource_customizer.rb @@ -27,8 +27,6 @@ def datasource(logger) def add_datasource(datasource, options) @stack.queue_customization(lambda { - # TODO: add call logger - if options[:include] || options[:exclude] publication_decorator = Decorators::Publication::PublicationDatasourceDecorator.new(datasource) publication_decorator.keep_collections_matching(options[:include], options[:exclude]) @@ -61,7 +59,7 @@ def add_chart(name, &definition) end def use(plugin, options) - # TODO: to implement + push_customization { plugin.new.run(self, nil, options) } end def customize_collection(name, handle) diff --git a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/collection.rb b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/collection.rb index 350be0378..95a4ef3ee 100644 --- a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/collection.rb +++ b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/collection.rb @@ -16,9 +16,9 @@ def initialize(datasource, name, native_driver = nil) countable: false, searchable: false, charts: [], - segments: {} + segments: {}, + actions: {} } - @actions = {} end def enable_count @@ -50,9 +50,9 @@ def add_fields(fields) end def add_action(name, action) - raise Exceptions::ForestException, "Action #{name} already defined in collection" if @actions[key] + raise Exceptions::ForestException, "Action #{name} already defined in collection" if @schema[:actions].key?(name) - @actions[name] = action + schema[:actions][name] = action end def render_chart(_caller, name, _record_id)