Cel jest taki że użytkownik może budować własne formularze za pomocą edytora w javascripcie. Dane z edytora zapisywane są jako JSON w jednej kolumnie modelu form.
Gdy ktoś wypełni formularz rekord odpowiedzi zapisuje dane także jako JSON, wcześniej tez kopiuje sobie do kolumny form_structure strukturę pól z modelu form. Moim celem było zasymulowanie żeby Response traktował pola które są w data tak jak normalne atrybuty, czyli odczyt i zapis artrybutu, validacja itp, no i z grubsza się udało poza tymi nachodzącymi na siebie walidacjami.
Nie moge użyć tutaj dziedziczenia bo typów formularzy mogą być setki, każdy inne pola.
Oto kod modułu, kontrolera oraz modelu:
[code=ruby]module SerializeExtensions
def self.included(base)
base.after_initialize :collect_fields, :add_accessors, unless: lambda {|r| r.form_structure.blank? }
base.before_validation :add_validations, unless: lambda {|r| r.form_structure.blank? }
end
private
def collect_fields
@fields = JSON.parse(form_structure)
end
def add_accessors
serialized_attr_accessor :data, @fields.collect {|e| e[‘name’]}
end
def add_validations
fields_not_blank = @fields.select {|f| f[‘required’] == ‘checked’}.collect {|f| f[‘name’]}
unless fields_not_blank.empty?
self.class.instance_eval do
validates_with SerializedPresenceValidator, fields: fields_not_blank
end
end
end
def serialized_attr_accessor(serialized, accessors)
accessors.each do |k|
self.class.instance_eval do
define_method("#{k}") do
self[serialized] && self[serialized][k]
end
define_method("#{k}=") do |value|
self[serialized] ||= {}
self[serialized][k] = value
end
end
end
end
end
class ResponsesController < ApplicationController
def create
@response = @form.responses.build(data: params[:response])
@response.user = current_user
if @response.save
redirect_to forms_path
else
render :new
end
end
end
class Response < ActiveRecord::Base
serialize :data, JSON
attr_accessible :data, :form_structure
belongs_to :form
belongs_to :user
after_initialize :attach_current_form_structure
validate :data, :form_id, :form_structure, :user_id, presence: true
include SerializeExtensions
private
def attach_current_form_structure
self.form_structure = self.form.structure if self.form
end
end[/code]