Giter VIP home page Giter VIP logo

Comments (13)

JoeKaldas avatar JoeKaldas commented on May 29, 2024 1

@DmitryTsepelev so I figured it out. It was pretty straight forward haha

It's the same approach you suggested. Only difference is I didn't override StoreModel module

I suggest you can also add it to the readme as an inheritance feature.
I'll close the issue now. Thanks again!

module ApplicationController
  module_function

  def helpers
    Module.new do
      module_function

      def exclude_id_from_columns(model)
        case model
        when "team" then { name: { type: :string }, email: { type: :string } }
        when "project" then { name: { type: :string }, client: { type: :string } }
        end
      end

      def get_required_columns_by_validation(model, _type)
        { name: { type: :string } }
      end
    end
  end
end

# app code

class ContentConfiguration
  include StoreModel::Model

  def self.configure_as(model)
    ApplicationController.helpers.exclude_id_from_columns(model).each do |key, value|
      attribute key.to_sym, value[:type].to_sym
    end

    ApplicationController.helpers.get_required_columns_by_validation(model, 'presence').each do |key, value|
      validates key.to_sym, presence: true
    end
  end
end

class ProjectConfiguration < ContentConfiguration
  configure_as('project')
end

class TeamConfiguration < ContentConfiguration
  configure_as('team')
end

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024 1

Good to know! I'll be very grateful if you could make a documentation PR with your snippet

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024

Hi @JoeKaldas!

I believe you could do it using a plain Ruby: define a module with a method that initializes the attribute and validations by its name and call this method for each attribute:

module StoreModel
  module Model
    def attribute(attribute_name, attribute_type)
      puts "attribute defined: #{attribute_name} (#{attribute_type})"
    end

    def validates(attribute_name, options)
      puts "validation defined: #{attribute_name} (#{options})"
    end
  end
end

module SharedAttributeConfig
  include StoreModel::Model

  def attribute_with_shared_config(attribute_name)
    attribute attribute_name, :string
    validates attribute_name, presence: true
  end
end

class MyModel
  extend SharedAttributeConfig

  attribute_with_shared_config :first
  attribute_with_shared_config :second
end

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

Hi @DmitryTsepelev

Thank you for your answer. However I think you misunderstood me, let me explain more.

I have a single table database, called Content and this table has an enum column that tells me the record belongs to which "table". So let's say I have 2 enum keys "team" and "project"
And then a json column in content table that has the columns of each table team/project

So let's say team has name/email (again those are dynamic and could change)
And project has title/client

Let me share a bit of the code. So this is the team's configuration file
I have a json schema that I read from where everything is defined.
So Project's configuration would be exactly the same except that I want to set "model" variable to "project" instead
So I don't want to make another configuration that has exactly the same code, just with "model" variable changed

I just want to have one configuration and pass the model variable to it

I hope it's clear

class TeamConfiguration
  model = 'team'
  include StoreModel::Model

  ApplicationController.helpers.exclude_id_from_columns(model).each do |key, value|
      attribute key.to_sym, value[:type].to_sym
  end

  ApplicationController.helpers.get_required_columns_by_validation(model, 'presence').each do |key, value|
      validates key.to_sym, presence: true
  end
end

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024

You cannot do it out of the box using the library DSL, but my initial approach still works, you can generate there configuration classes using inheritance/composition and helper method:

# fake code to make it runnable

module StoreModel
  module Model
    def self.included(base)
      base.extend(Module.new do
        def attribute(attribute_name, attribute_type)
          puts "attribute defined: #{attribute_name} (#{attribute_type})"
        end

        def validates(attribute_name, options)
          puts "validation defined: #{attribute_name} (#{options})"
        end
      end)
    end
  end
end

module ApplicationController
  module_function

  def helpers
    Module.new do
      module_function

      def exclude_id_from_columns(model)
        case model
        when "team" then { name: { type: :string }, email: { type: :string } }
        when "project" then { name: { type: :string }, client: { type: :string } }
        end
      end

      def get_required_columns_by_validation(model, _type)
        { name: { type: :string } }
      end
    end
  end
end

# app code

class ContentConfiguration
  include StoreModel::Model

  def self.configure_as(model)
    ApplicationController.helpers.exclude_id_from_columns(model).each do |key, value|
      attribute key.to_sym, value[:type].to_sym
    end

    ApplicationController.helpers.get_required_columns_by_validation(model, 'presence').each do |key, value|
      validates key.to_sym, presence: true
    end
  end
end

class ProjectConfiguration < ContentConfiguration
  configure_as('project')
end

class TeamConfiguration < ContentConfiguration
  configure_as('team')
end

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

Hi @DmitryTsepelev

Thanks again.

I did the following

  1. Created a configurations folder under app
  2. Created 3 files under this folder. One for ContentConfiguration, TeamConfiguration, Project Configuration
  3. Here is TeamConfiguration for example
class TeamConfiguration < ContentConfiguration
  configure_as('team')
end

And I have a team model that inherits from content model and has the following

class Team < Content
  attribute :data, TeamConfiguration.to_type
end

But I'm getting following error:

undefined method `type' for TeamConfiguration:Class

Thanks again

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024

Is there a line that calls this #type method in the stacktrace?

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

Log doesn't say anything. Just this

But the puts for attributes and validations are printed

NoMethodError (undefined method `to_type' for TeamConfiguration:Class):

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024

Looks like I figured it out, the only change is in the ContentConfiguration class (see the comment):

# fake code to make it runnable

module StoreModel
  module Model
    def self.included(base)
      base.include(Module.new do
        def attribute(attribute_name, attribute_type)
          puts "attribute defined: #{attribute_name} (#{attribute_type})"
        end

        def validates(attribute_name, options)
          puts "validation defined: #{attribute_name} (#{options})"
        end
      end)
    end

    def to_type
      puts "StoreModel::Model#to_type"
    end
  end
end

module ApplicationController
  module_function

  def helpers
    Module.new do
      module_function

      def exclude_id_from_columns(model)
        case model
        when "team" then { name: { type: :string }, email: { type: :string } }
        when "project" then { name: { type: :string }, client: { type: :string } }
        end
      end

      def get_required_columns_by_validation(model, _type)
        { name: { type: :string } }
      end
    end
  end
end

# app code

class ContentConfiguration
  def self.configure_as(model)
    self.class.include StoreModel::Model # this line was changed

    ApplicationController.helpers.exclude_id_from_columns(model).each do |key, value|
      attribute key.to_sym, value[:type].to_sym
    end

    ApplicationController.helpers.get_required_columns_by_validation(model, 'presence').each do |key, value|
      validates key.to_sym, presence: true
    end
  end
end

class ProjectConfiguration < ContentConfiguration
  configure_as('project')
end

class TeamConfiguration < ContentConfiguration
  configure_as('team')
end

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

Hello, now I'm getting the following error and the stacktrace

NameError (undefined local variable or method `attributes' for #<Class:0x00007fb9490c5260>)
Did you mean?  attribute
Traceback (most recent call last):
	35: from bin/rails:6:in `<main>'
	34: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/dependencies.rb:324:in `require'
	33: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/dependencies.rb:291:in `load_dependency'
	32: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/dependencies.rb:324:in `block in require'
	31: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	30: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	29: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	28: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	27: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	26: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/commands.rb:18:in `<main>'
	25: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/command.rb:46:in `invoke'
	24: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/command/base.rb:69:in `perform'
	23: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
	22: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
	21: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
	20: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/commands/console/console_command.rb:102:in `perform'
	19: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/commands/console/console_command.rb:19:in `start'
	18: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/railties-6.0.3.4/lib/rails/commands/console/console_command.rb:70:in `start'
	17: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:400:in `start'
	16: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:471:in `run'
	15: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:471:in `catch'
	14: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:472:in `block in run'
	13: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:537:in `eval_input'
	12: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `each_top_level_statement'
	11: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `catch'
	10: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `block in each_top_level_statement'
	 9: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `loop'
	 8: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:154:in `block (2 levels) in each_top_level_statement'
	 7: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/ruby-lex.rb:182:in `lex'
	 6: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:518:in `block in eval_input'
	 5: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:704:in `signal_status'
	 4: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb.rb:519:in `block (2 levels) in eval_input'
	 3: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/irb/input-method.rb:290:in `gets'
	 2: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/forwardable.rb:230:in `input='
	 1: from /Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/2.7.0/reline.rb:133:in `input='
/Users/joekaldas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/store_model-0.8.0/lib/store_model/model.rb:40:in `==': undefined local variable or method `attributes' for #<Class:0x00007fb94d8bf778> (NameError)
Did you mean?  attribute

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

Hi @DmitryTsepelev
Any help with the previous error?

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 29, 2024

Sorry, we have a loooong New Year holiday season here in Russia 🙃

So it looks like something is wrong in the order of calls, and in order to debug that I'll have to rebuild the app from scratch (which is kinda time consuming), so let me explain what I tried to do and it will probably help you to fix the problem.

There is a base class (ContentConfiguration) which has the class method configure_as. Each child class calls the method and passes the name of the entity to it. The method does two things:

  1. Configures the class to be a StoreModel (something might be wrong here, you could try to use a regular include in each child model
  2. Configures validations according to the helper methods

from store_model.

JoeKaldas avatar JoeKaldas commented on May 29, 2024

It's okay! Appreciate the response :)

Yes I understand the approach you're using. Was just stuck since the error is store model related.
But I'll look into it and let you know if I reach anything.

Thanks a lot again!

from store_model.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.