1

I would highly appreciate if someone could critique this approach for me.

I'm building an application where a user can define several attributes & generate a form to share with his users, much like Wufoo.

This is my approach.

User has_many sources & Source embeds_many source_attributes

Here, all of the user defined fields are stored in SourceAttributes. When i need to generate a form, I generate a model on the fly like this.

#source.rb

def initialize_set
model_name = self.set_name.gsub(' ','').classify

# Unique Class name
klass_name = "#{model_name}#{self.user.id}"
object = self

klass = Class.new do
  include Mongoid::Document

 # Collection names have to be set manually or they don't seem to work
  store_in collection: self.collection_name

 # Pick up attributes from SourceAttribute & define fields here
  object.source_attributes.each do |m|
    field m.field_name.gsub(' ','').underscore, type: object.class.mapping[m.field_type]
  end


  def self.collection_name
    self.name.tableize
  end

 end

 # I get a warning here when the class is re-loaded. Should i worry? I'm considering Object.send :remove_const here
 Object.const_set klass_name, klass

end

With this approach, I'll have a separate collection for every form the User defines. This seems to work but I have a couple of problems.

  • Type Safety

The fields I generate above don't seem to be type safe. I am able to save a String in an Integer field.

The type seems to have been set correctly. I double checked this by calling fields on klass & checking the options[:type] attribute.

I'm using simple form & it doesn't recognize type automatically. I have to mention it explicitly using as:

  • Scalability

I'm not sure if my approach of generating models on the fly is correct. I've never seen anyone use this before.

Moved to a separate question. Please check comments.

UPDATE 1:

So I was wrong. My model is type safe, but it seems to fail silently. Is there a way I can make it throw an exception?

# age is correctly defined as an Integer
klass.fields.slice "age"
=> {"age"=>#<Mongoid::Fields::Standard:0xb7edf64 @name="age", @options={:type=>Integer, :klass=>Engineer50bc91a481ee9e19ab000006}, @label=nil, @default_val=nil, @type=Integer>}

# silently sets age to 0
 klass.create!(age: "ABC")
 => #<Engineer50bc91a481ee9e19ab000006 _id: 50cff12181ee9e16f1000003, _type: nil, employee_code: nil, name: nil, age: 0, years: nil, number: nil>

 # returns true when saved
 object = klass.new
 object.age = "ABC"
  => "ABC" 
 object.save
  => true 

PS: This is my first time using mongoid :)

UPDATE 2:

My problem with Integer validation might be with Ruby & not mongoid.

As mentioned in my previous update,

# silently sets age to 0
klass.create!(age: "ABC")
 => #<Engineer50bc91a481ee9e19ab000006 _id: 50cff12181ee9e16f1000003, _type: nil, employee_code: nil, name: nil, age: 0, years: nil, number: nil>

I believe "ABC" is being typecasted

"ABC".to_i
 => 0 

I tried to overcome this problem by using validates_numericality_of like this

object.model_attributes.where(field_type: "Number").map(&:field_name).each do |o|
 validates_numericality_of o.gsub(' ','').underscore.to_sym
end

Unfortunately, this checks for presence as well. I tried this workaround

validates_numericality_of o.gsub(' ','').underscore.to_sym, allow_nil: true

But this completely ignores the numericality validation. Tried allow_blank as well with no luck.

Rahul
  • 412
  • 4
  • 13
  • My question on **Numericality validation** deserves a separate question. Please find the same [here](http://stackoverflow.com/questions/13927637/mongoid-activemodel-numericality-validation-allow-nil-does-not-work) – Rahul Dec 18 '12 at 06:46

0 Answers0