开发者

Dynamic Custom Fields for Data Model

I am in the process of creating a dynamic database where user will be abl开发者_Python百科e to create resource type where he/she can add custom fields (multiple texts, strings, and files)

Each resource type will have the ability to display, import, export its data;

I've been thinking about it and here are my approaches. I would love to hear what do you guys think.

Ideas:

  1. just hashing all the custom data in a data field (pro: writing is easier, con: reading back out may be harder);

  2. children fields (the model will have multiple fields of strings, fields of text, and fields for file path);

  3. fixed number of custom fields in the same table with a key mapping data hash stored in the same row;

  4. Non-SQL approach, but then the problem would be generating/changing models on the fly to work with different custom fields;


Firstly you can create few models:
- StringData
- BooleanData
- TextData
- FileData
etc (all data and fields formats you need)

Each model will refferenced to some project, wich will contain information about fields

IE:

class Project < ActiveRecord::Base
  has_many :project_fields
  has_many :string_datas :through => project_fields
  has_many :file_datas :through => project_fields
  has_many :boolean_datas :through => project_fields
  etc ...
end

class ProjectField < ActiveRecord::Base
  # title:string field_type:string project_id:integer name:string
  belongs_to :project
  has_many :string_datas
  has_many :file_datas
  has_many :boolean_datas
  etc ...
end

class StringData < ActiveRecord::Base
  # data:string project_field_id:integer
  belongs_to :project_field, :conditions => { :field_type => 'String' }
end

class FileData < ActiveRecord::Base
  # data:file project_field_id:integer
  belongs_to :project_field, :conditions => { :field_type => 'File' }
end

project = Project.new
project.project_fields.new(:title => "Product title", :field_type => "String", :name => 'product_title')
project.project_fields.new(:title => "Product photo", :field_type => "File", :name => 'product_photo')
project.save

<% form_for project do |f| -%>
  <% project.project_fields.each do |field| -%>
    <%= field_setter field %>
    #=> field_setter is a helper method wich creates form element (text_field, text_area, file_field etc) for each type of prject_field
    #=> ie: if field.field_type == 'String' it will return
    #=> text_field_tag field.name => <input name='product_name' />
  <% end -%>
<% end -%>

And create (update) method

def create
  project = Project.new(params[:project])
  project.project_fields.each do |field|
    filed.set_field params[field.name]
    # where set_field is model method for setting value depending on field type
  end
  project.save
end

It is not tested and optimized but it just showing the way you can implement it.

UPDATE: I've updated code but It's only model, you have to think yourself a little :) and you can try to find out another implementation


Why not just create a model for DynamicField?

Columns:

  t.integer :dynamic_field_owner_id
  t.string :dynamic_field_owner_type
  t.string :name, :null => false
  t.string :value
  t.string :value_type_conversion, :default => 'to_s'
  # any additional fields from paperclip, has_attachment, etc.
  t.timestamps

model class:

class DynamicField > ActiveRecord::Base

  belongs_to :dynamic_field_owner, :polymorphic => true

  validates_presence_of :name
  validates_inclusion_of :value_type_conversion, :in => %w(to_s to_i to_f)
  validates :value_or_attachment

  def value
    read_attribute(:value).send(value_type_conversion)
  end

 private

 def value_or_attachment
   unless value? || file?
     errors.add_to_base('Must have either value or file')
   end
 end

end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜