数据库模型中的 Rails 建模和/或逻辑,带有 Acts As Taggable 开启

Rails Modeling And/Or Logic in a database model with Acts As Taggable On

提问人:Romuloux 提问时间:11/8/2023 最后编辑:Romuloux 更新时间:11/8/2023 访问量:31

问:

我正在尝试对逻辑进行建模,该逻辑将允许基于布尔逻辑的用户定义搜索返回 的某个子集。下面是代码。它没有经过测试,可能有错别字,因为它写在 SO 上只是为了思考这个问题。TaggedModel

# Basic widget, could be anything.
class TaggedModel < ActiveRecord
  acts_as_taggable_on
end

# Represents a single piece of logic that can
# be chained together to create complex queries.
# Currently this would create n + 1 db queries, n = number of statements 
# @attr inner_join_type [String] And/Or when it comes to tags within the statement.
# @attr preceding_statement [TagStatement] @optional The statement preceding this one.
# @attr preceding_statement_join_type [String] @optional And/Or to apply with
class TagStatement < ActiveRecord
  acts_as_taggable_on

  JOIN_TYPES = ['or','and']

  belongs_to :preceding_statement, optional: true, class: 'TagStatement'
  has_one :subsequent_statement, class: 'TagStatement', foreign_key: :preceding_statement_id

  validates :inner_join_type, presence: true, inclusion: { in: JOIN_TYPES }
  validates :preceding_statement_join_type, presence: true, inclusion: { in: JOIN_TYPES }, if: :preceding_statement

  # Scope for all master statements.
  # @return [ActiveRecord::Relation]
  def self.master_statements
    where(preceding_statement_id: nil)
  end

  # If the statement is a master statement.
  # @return [Boolean]
  def is_master
    preceding_statement_id.nil?
  end
  
  # The basic statement applying to a single tagged model.
  # @return [ActiveRecord::Relation<TaggedModel>]
  def statement
    if inner_join_type === 'or'
      TaggedModel.tagged_with(tags, any: true)
    else
      TaggedModel.tagged_with(tags, match_all: true)
    end
  end
  
  # Chains all the statements from this record and subsequent records.
  # TODO: Write all the logic in here. Some sort of looping statement to go
  # through all the records returned by the statements of the current model
  # plus any subsequent models adding removing as necessary the ids from the
  # ids array.
  # @return [ActiveRecord::Relation<TaggedModel> The tagged models that apply given statement logic
  def chained_statement(ids=[])
    ids = []
    if is_master
      ids = (ids + statement.&ids).uniq # Uniq probably extra here
    else
      if preceding_statement_join_type == 'or'
        ids.push(statement.&ids).uniq # Or so just add all ids together
      else
        ids = ids & statement.&ids # AND so remove any ids not present in statement ids.
      end
    end
    if subsequent_statement
      ids = subsequent_statement.chained_statement(ids)
    end
    ids
  end
end

用户可以执行的操作示例:

创建一组语句,用于查找标记有

(“蓝色”或“红色”)AND ('green') => 标记为蓝色或红色但始终带有绿色的模型。 (“蓝色”和“红色”)OR ('green' AND 'RED') => 标有蓝色和红色或绿色和红色的型号。

我觉得我走在正确的轨道上,但也许我正在重新发明轮子?

Ruby-on-Rails ActiveRecord 充当 Taggable-On

评论

0赞 zaphodbln_ 11/10/2023
是否有理由为规则集创建实际的 ActiveRecord-Model(导致数据库中的记录)?
0赞 Romuloux 11/11/2023
@zaphodbln_ 只是永恒。我宁愿创建一个新的模型/表,也不愿做像JSON列或其他事情。它使我更容易将逻辑分开。如果这就是你要问的。

答: 暂无答案