class Netfira::WebConnect::Model::Relation

Attributes

Public Class Methods

for(class_a, class_b) click to toggle source
# File lib/netfira/web_connect/model/relation.rb, line 123
def for(class_a, class_b)
  name = [class_a, class_b].map{ |c| (c.is_a?(Class) ? c : c.class).name.demodulize }.sort.join 'To'
  Models.const_get name if Models.const_defined? name
end
for!(*args) click to toggle source
# File lib/netfira/web_connect/model/relation.rb, line 128
def for!(*args)
  self.for(*args).tap do |result|
    raise args.map { |c| (Class === c ? c : c.class).name.demodulize.pluralize }.join ' are not related to ' unless result
  end
end
materialize(name_a, name_b) click to toggle source
# File lib/netfira/web_connect/model/relation.rb, line 11
def materialize(name_a, name_b)

  # The new class, e.g. Models::ImageToProduct
  klass = Class.new(self)
  Models.const_set "#{name_a}To#{name_b}", klass

  # An array of related classes, e.g. [Models::Image, Models::Product]
  klass.related_classes = [name_a, name_b].map{ |n| Models.const_get n.camelize.singularize }

  # Sets up paranoia, including a with_deleted scope for consistency
  if Netfira::WebConnect.paranoia?
    klass.acts_as_paranoid
  else
    def klass.with_deleted; self end
  end

  # Enables finding by origin IDs, e.g.:
  # ImageToProduct.find_by_origin_ids(image: 'apple.jpg', product: 'apple', shop: 5)
  find_by_origin_ids = proc do |**args|

    # The table of the current class, e.g. nf_images_to_products
    join_table = klass.arel_table

    # The scope we're building
    scope = klass

    # Include a shop in the scope if one is given
    shop = args[:shop]
    if shop
      shop = shop.id if Models::Shop === shop
      raise "`shop` must be an integer or an instance of #{Models::Shop.name}" unless Fixnum === shop
    end

    # Join each class and add where clauses
    klass.related_classes.each do |related_class|

      # The related table, e.g. nf_images
      related_table = related_class.arel_table

      # The argument expected to identify the relevant row of the table, e.g. :image
      origin_id_arg = related_class.single_name.to_sym

      # The origin ID to find in the table, e.g. 'apple.jpg'
      origin_id = args[origin_id_arg] or raise "Missing argument `#{origin_id_arg}`"

      # The column of the related table in which to seek the origin ID, e.g. :file_name
      origin_key = related_class.origin_key.to_sym

      # The column on which to join the relation table, e.g. :image_id
      join_key = :"#{related_class.single_name}_id"

      # Join the related table, e.g.:
      # INNER JOIN "nf_images" ON "nf_images_to_products"."image_id" = "nf_images"."id"
      scope = scope.joins join_table.join(related_table).on(join_table[join_key].eq related_table[:id]).join_sql

      # Look for the origin ID, e.g.:
      # WHERE "nf_images"."file_name" = 'apple.jpg'
      scope = scope.where related_table[origin_key].eq origin_id

      # Limit to the given shop, e.g.:
      # AND "nf_images"."shop_id" = 5
      scope = scope.where related_table[:shop_id].eq shop if shop
    end

    # Only look for one record.
    scope.limit 1
  end
  klass.scope :find_by_origin_ids, find_by_origin_ids
end
table_name() click to toggle source
# File lib/netfira/web_connect/model/relation.rb, line 115
def table_name
  @table_name ||= if self == Model::Relation
    Models::Table.table_name
  else
    Netfira::WebConnect.db_table_prefix(related_classes.map(&:plural_name).join '_to_').to_s
  end
end

Public Instance Methods

records() click to toggle source
# File lib/netfira/web_connect/model/relation.rb, line 136
def records
  self.class.current_scope = nil if Netfira::WebConnect.paranoia? # Fixes a bug triggered by paranoia
  self.class.related_classes.map{ |klass| __send__ klass.single_name.to_sym }
end