Skip to content

Instantly share code, notes, and snippets.

@goshacmd
Created January 16, 2013 19:58
Show Gist options
  • Save goshacmd/4550323 to your computer and use it in GitHub Desktop.
Save goshacmd/4550323 to your computer and use it in GitHub Desktop.
Mongoid inline relation definitions. Ruby makes it so easy ❤️
# Mongoid inline relation definitions. Ruby makes it so easy.
# (`data` is effectively just a shortcut for `inline_embed_one(:data)` there.)
#
# Yes, it would make sense to create separate models, but my case is different.
# This application is used to track events of other apps, such as purchase, and
# it makes *more* sense to embed all order-related data. Instead of having model
# overload for each event being tracked, I just define them inline.
class OrderEvent
include Analyzing::Event
event_for :shop
data do
field :total_price, type: Float
field :currency, type: String
field :total_price_usd, type: Float
field :name, type: String
inline_embed_one :customer do
field :first_name, type: String
field :last_name, type: String
field :email, type: String
end
inline_embed_many :line_items do
field :name, type: String
field :title, type: String
field :price, type: Float
field :quantity, type: Integer
field :sku, type: String
end
end
end
module MongoidExt
extend ActiveSupport::Concern
module ClassMethods
# Public: Define embeds_one inline. Class and actual relation will be
# created automatically for you.
#
# rel_name - The Symbol relation name. Class name will be created based
# on it. Additionally it will be used to define "embeds_one"
# relation.
# options - The Hash "embeds_one" options.
# block - The block used to define Mongoid Document.
#
# Examples
#
# class Some
# inline_embed_one :association_name do
# # embedded class definition here
# end
# end
def inline_embed_one(rel_name, options = {}, &block)
em_class_name = rel_name.to_s.camelize
em_class = Class.new
const_set(em_class_name, em_class)
em_class.tap do |klass|
klass.send(:include, Mongoid::Document)
klass.send(:include, MongoidExt)
klass.class_eval(&block)
end
embeds_one rel_name, options.merge(class_name: "#{name}::#{em_class_name}", autobuild: true)
end
# Public: Define embeds_many inline. Class and actual relation will be
# created automatically for you.
#
# rel_name - The Symbol relation name. Class name will be created based
# on it. Additionally it will be used to define "embeds_many"
# relation.
# options - The Hash "embeds_many" options.
# block - The block used to define Mongoid Document.
#
# Examples
#
# class Some
# inline_embed_many :association_name do
# # embedded class definition here
# end
# end
def inline_embed_many(rel_name, options = {}, &block)
em_class_name = rel_name.to_s.singularize.camelize
em_class = Class.new
const_set(em_class_name, em_class)
em_class.tap do |klass|
klass.send(:include, Mongoid::Document)
klass.send(:include, MongoidExt)
klass.class_eval(&block)
end
embeds_many rel_name, options.merge(class_name: "#{name}::#{em_class_name}")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment