Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails module with Mongoid

I'm trying to extend a few of my model classes to an "Asset" class. Each of the four types of Assets will be able to generate a slug off a set_callback(:save, :before) Consequently, instead of writing four methods that are the same, I'd like them to extend an Asset class that would have the set_callback (as well as other methods).

At first I tried simply having them extend the Asset class but I ran into problems where when I saved one of the assets to the database (mongo), the collection they inserted into was called Asset rather than their own name.

After I googled around people seem to recommend using modules instead. So I've tried that:

module Asset
  field :slug, :type => String

  set_callback(:save, :before) do |document|
    # make document.slug = to whatever
  end
end

class Video
  include Mongoid::Document
  include Asset
  field :video_name, :type => String
  field :description, :type => String
  field :some_more_fields, :type => String
end

But I get some errors when I include Asset:

'undefined method `field' for Asset:Module'

Note: I'm using Mongoid

like image 810
K2xL Avatar asked Mar 09 '12 17:03

K2xL


2 Answers

The method field is not known in the context of the Asset module. So you have to call field only when the module is included:

  module Asset
    def self.included(base)
      base.send(:field, :slug, :type => String)
    end
  end

Edit: wrapped code in code block

like image 170
sailor Avatar answered Nov 03 '22 06:11

sailor


Ok, using concerns makes this much much easier and nicer to write:

module Asset
 include extend ActiveSupport::Concern
  included do
   field: slug, type: String
   before_create: :notify_on_create
   scope: my_scope, ->(var) { where(slug: var) }
  end
 end
end

see http://api.rubyonrails.org/classes/ActiveSupport/Concern.html for more details.

like image 45
Alex Avatar answered Nov 03 '22 08:11

Alex