avo-hq / avo

Build Ruby on Rails apps 10x faster
https://avohq.io
Other
1.48k stars 232 forks source link

Default settings #2699

Open adrianthedev opened 5 months ago

adrianthedev commented 5 months ago

Context

We want to give the ability to developers to set certain settings to a certain value globally.

For example, set all the belongs_to fields to have the searchable value to true.

Explorations


  config.default_settings = {
    fields: {
      belongs_to: {
        searchable: false,
        polymorphic_as: false,
        relation_method: false,
      }
    },
    "fields.belongs_to.searchable": false,
    "fields.belongs_to.polymorphic_as": false,
    "fields.belongs_to.relation_method": false,
  }

@searchable = default_attribute("fields.belongs_to.searchable", args[:searchable] == true)
@polymorphic_as = default_attribute("fields.belongs_to.polymorphic_as", args[:can_create].nil? ? true : args[:can_create])

      def default_attribute(key, default)
        if value_exists?(key)
          value(key)
        else
          default
        end
      end
Paul-Bob commented 5 months ago

Possible approaches (none of the code was executed/tested):

1. Merge defaults on boot

  1. Create a hash for each field defaults, let's take an example on Avo::Fields::BelongsTo
BELONGS_TO_DEFAULTS = {
  searchable: false,
  can_create: true
}
  1. Collect user defaults for that field (to be decided where and how)

    USER_BELONGS_TO_DEFAULTS = {
    searchable: true,
    can_create: true
    }
  2. On boot merge options and override avo defaults with user defaults: BELONGS_TO_DEFAULTS.merge!(USER_BELONGS_TO_DEFAULTS)

  3. Use the merged defaults hash to access default values:

    def initialize(id, **args, &block)
    # ...
    @searchable = args[:searchable].nil? ? BELONGS_TO_DEFAULTS[:searchable] : args[:searchable]
    @can_create = args[:can_create].nil? ? BELONGS_TO_DEFAULTS[:can_create] : args[:can_create]
    # ...
    end
  4. Optional: DRY refactor

    
    def initialize(id, **args, &block)
    # ...
    initialize_option :searchable, args
    initialize_option :can_create, args
    # ...
    end

def initialize_option(option, args) user_option = args.dig(option)

instance_variable_set(:"@#{option}", user_option.nil? ? BELONGS_TO_DEFAULTS.dig(option) : user_option) end


## 2. Check for user default on each initialize
1. Collect user defaults for that field (to be decided where and how)
```ruby
USER_BELONGS_TO_DEFAULTS = {
  searchable: true,
  can_create: true
}
  1. When user option is not provided check for user defaults first then apply avo defaults if not present

    def initialize(id, **args, &block)
    # ...
    @searchable = if args[:searchable].nil?
    user_default = USER_BELONGS_TO_DEFAULTS[:searchable]
    user_default.nil? ? false : user_default
    else
    args[:searchable]
    end
    
    @can_create = if args[:can_create].nil?
    user_default = USER_BELONGS_TO_DEFAULTS[:can_create]
    user_default.nil? ? true : user_default
    else
    args[:can_create]
    end
    # ...
    end
  2. Optional: DRY refactor

    
    def initialize(id, **args, &block)
    # ...
    initialize_option :searchable, args
    initialize_option :can_create, args
    # ...
    end

def initialize_option(option, args) user_option = args.dig(option)

value = if user_option.nil? user_default = USER_BELONGS_TO_DEFAULTS.dig(option) user_default.nil? ? false : user_default else user_option end

instance_variable_set(:"@#{option}", value) end



# Things to have in consideration
1. Performance. We should identify the approach with less performance impact
2. Presence checks. We should validate present by using `nil?` method instead `present?` because the presence method can return `false` if the value is intentionally setted as `false` or empty.
3. Complexity. Lets ensure that the complexity of this mechanism is maintained as low as possible to preserve easy readability and maintainability
github-actions[bot] commented 4 months ago

This issue has been marked as stale because there was no activity for the past 15 days.