Динамические настраиваемые поля для модели данных - PullRequest
4 голосов
/ 07 апреля 2010

Я нахожусь в процессе создания динамической базы данных, где пользователь сможет создать тип ресурса, в который он / она может добавлять настраиваемые поля (несколько текстов, строк и файлов)

Каждый тип ресурса будет иметь возможность отображать, импортировать, экспортировать свои данные;

Я думал об этом, и вот мои подходы. Я хотел бы услышать, что вы, ребята, думаете.

Идеи:

  1. просто хэширование всех пользовательских данных в поле данных (pro: запись проще, con: чтение может быть труднее);

  2. дочерние поля (модель будет иметь несколько полей строк, полей текста и полей для пути к файлу);

  3. фиксированное количество настраиваемых полей в одной таблице с хешем данных отображения ключей, хранящихся в той же строке;

  4. Не-SQL-подход, но тогда проблема заключается в создании / изменении моделей на лету для работы с различными настраиваемыми полями;

Ответы [ 2 ]

6 голосов
/ 07 апреля 2010

Во-первых, вы можете создать несколько моделей:
- StringData
- BooleanData
- TextData
- FileData
и т. д. (все необходимые форматы данных и полей)

Каждая модель будет привязана к какому-либо проекту, который будет содержать информацию о полях

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 -%>

И метод создания (обновления)

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

Он не протестирован и не оптимизирован, а просто показывает, как вы можете его реализовать.

ОБНОВЛЕНИЕ: я обновил код, но это только модель, вам нужно немного подумать :) и вы можете попытаться найти другую реализацию

3 голосов
/ 07 апреля 2010

Почему бы просто не создать модель для DynamicField?

Колонки:

  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

модель класса:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...