diff --git a/app/controllers/admin/surveys_controller.rb b/app/controllers/admin/surveys_controller.rb index 2d95401..f9a5a27 100644 --- a/app/controllers/admin/surveys_controller.rb +++ b/app/controllers/admin/surveys_controller.rb @@ -217,58 +217,9 @@ class Admin::SurveysController < OrbitAdminController def duplicate_it - @new_survey = QuestionnaireSurvey.new - - @survey.attributes.each do |key, value| - unless ['_id', 'created_at', 'updated_at', 'update_user_id'].include? key - if @survey.respond_to?(key + '_translations') - @new_survey.send(key + '_translations=', value) - else - @new_survey.write_attribute(key, value) - end - end - end - @survey.survey_questions.all.each do |question| - new_question = @new_survey.survey_questions.new - question.attributes.each do |key, value| - unless ['_id', 'survey_id'].include? key - if question.respond_to?(key + '_translations') - new_question.send(key + '_translations=', value) - else - new_question.write_attribute(key, value) - end - end - end - question.survey_question_options.all.each do |option| - new_option = new_question.survey_question_options.new - option.attributes.each do |key, value| - unless ['_id', 'survey_question_id'].include? key - if option.respond_to?(key + '_translations') - new_option.send(key + '_translations=', value) - else - new_option.write_attribute(key, value) - end - end - end - end - question.survey_question_radiogroups.all.each do |radiogroup| - new_radiogroup = new_question.survey_question_radiogroups.new - radiogroup.attributes.each do |key, value| - unless ['_id', 'survey_question_id'].include? key - if radiogroup.respond_to?(key + '_translations') - new_radiogroup.send(key + '_translations=', value) - else - new_radiogroup[key] = value - end - end - end - end - end - + @new_survey = QuestionnaireSurvey.new(:copy_id=>@survey.id,:except_clone_relations=>["survey_answers"]) @new_survey.create_user_id = current_user.id @new_survey.update_user_id = current_user.id - @new_survey.uid = nil - @new_survey.save! respond_to do |format| diff --git a/app/models/questionnaire_survey.rb b/app/models/questionnaire_survey.rb index d4a7e4f..469be20 100644 --- a/app/models/questionnaire_survey.rb +++ b/app/models/questionnaire_survey.rb @@ -13,6 +13,8 @@ class QuestionnaireSurvey scope :can_display, ->{where(is_hidden: false)} + field :copy_id + field :except_clone_relations, :type=>Array, :default => [] field :title, as: :slug_title, type: String, localize: true field :description, :localize => true @@ -40,8 +42,8 @@ class QuestionnaireSurvey # validates :title, :presence => { :message => I18n.t("survey.title") } has_many :survey_questions, :autosave => true, :dependent => :destroy - has_many :survey_answers, :dependent => :destroy - has_many :survey_sections, :dependent => :destroy + has_many :survey_answers, :autosave => true, :dependent => :destroy + has_many :survey_sections, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :survey_questions, :allow_destroy => true @@ -49,7 +51,13 @@ class QuestionnaireSurvey has_many :survey_paginations, :autosave => true, :dependent => :destroy accepts_nested_attributes_for :survey_paginations, :allow_destroy => true - + before_create do + if self.copy_id.present? + clone_new(true) + self.created_at = DateTime.now + self.updated_at = DateTime.now + end + end def update_user User.find(update_user_id) rescue nil end @@ -149,7 +157,207 @@ class QuestionnaireSurvey def expired? (self.deadline < Time.now) rescue false end - + def clone_new(clone_mode=false) + @records_all = {} + if clone_mode + clone_target = self.class.find(object.copy_id) rescue nil + else + clone_target = self + end + new_object,clone_target = clone_new_for_object(self,clone_target,clone_mode) + new_object + end + def clone_new_for_object(object,clone_target=nil,clone_mode=false) + if clone_mode + new_object = object + clone_target = object.class.find(object.copy_id) rescue nil if clone_target.nil? + else + clone_target = object if clone_target.nil? + new_object = object.dup + end + return if (self.except_clone_relations.to_s.include?(new_object.class.to_s.underscore) rescue false) + @records_all["#{new_object.class.to_s.underscore.singularize}_ids"] = {} if @records_all["#{new_object.class.to_s.underscore.singularize}_ids"].nil? + begin + @records_all["#{new_object.class.to_s.underscore.singularize}_ids"][clone_target.id] = object.id + rescue + nil + end + if !clone_target.nil? && !new_object.nil? + initialize_fields = ["uid","created_at","updated_at"] + initialize_fields.each do |f| + new_object.send("#{f}=",nil) if new_object.fields.keys.include?(f) + end + relations_fields = clone_target.relations.except("impressions").keys + all_fields = clone_target.fields.keys - relations_fields + all_fields = all_fields - relations_fields.map{|k| "#{k}_id"} + all_fields = all_fields - relations_fields.map{|k| "#{k.singularize}_ids"} + new_object_class_name = new_object.class.to_s.underscore + relations_fields = clone_target.relations.except("impressions").keys + unsort_relation_keys = clone_target.relations.keys + unless @parent_level + fields_to_delete = [new_object_class_name] + tmp_relations_fields = [new_object_class_name] + while relations_fields.count > 0 + tmp_singularize_relations_fields = tmp_relations_fields.map{|f| f.singularize} + approve_append = nil + relations_fields.each do |k| + belongs_to_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :belongs_to}.keys + has_many_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :has_many}.keys + if (belongs_to_class - tmp_singularize_relations_fields).count == 0 + other_has_many_class = (has_many_class - unsort_relation_keys) + if other_has_many_class.count == 0 + tmp_relations_fields << k + else + result = other_has_many_class.map do |k| + belongs_to_class = k.classify.constantize.relations.select{|kk,v| v.macro == :belongs_to}.keys + has_many_class = k.classify.constantize.relations.select{|kk,v| v.macro == :has_many}.keys + if (belongs_to_class - tmp_singularize_relations_fields).count == 0 + true + else + fields_to_delete = fields_to_delete.concat(belongs_to_class) + tmp_relations_fields.concat(belongs_to_class) + false + end + end + if result.select{|t| !t}.count == 0 + if (fields_to_delete.map{|f| f.pluralize} - tmp_relations_fields).count == 0 + tmp_relations_fields << k + elsif clone_target.relations[k].class_name.constantize.fields.keys.include?("key") + tmp_relations_fields << k + elsif (clone_target.relations[k].class_name.constantize.relations.keys.map{|f| f.singularize} & fields_to_delete).count != 0 + approve_append = k + end + end + end + elsif !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore) && !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore.pluralize) + tmp_relations_fields << k + end + end + tmp_relations_fields << approve_append if approve_append.present? + approve_append = nil + relations_fields = relations_fields - tmp_relations_fields + end + relations_fields = tmp_relations_fields + fields_to_delete.each{|f| relations_fields.delete(f)} + @clone_mode = clone_mode + end + @parent_level = true + if clone_mode + all_fields.each do |f| + next if f == "uid" + unless new_object.send("#{f}_changed?") && new_object.send("#{f}_changed_from_default?") + new_object.send("#{f}=",clone_target.send(f)) + end + end + end + relations_fields.each do |f| + no_dup_flag = false + if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].macro == :has_one + no_dup_flag = new_object.send(f).present? + elsif clone_target.relations[f].macro == :has_many + no_dup_flag = new_object.send(f).to_a.count != 0 + elsif clone_target.relations[f].macro == :embeds_many #Fix localize fields + if new_object.send(f).to_a.count != 0 + need_fix_fields = new_object.send(f).to_a[0].fields.select{|k,v| (v.options[:localize] rescue false)}.keys + locale = I18n.locale.to_s + embeded_records = new_object.send(f).map do |embeded_record| + need_fix_fields.each do |f| + if (embeded_record[f][locale].class != String rescue false) + embeded_record.send("#{f}_translations=",embeded_record[f][locale]) + else + embeded_record.send("#{f}_translations=",embeded_record[f]) + end + end + embeded_record + end + new_object.send("#{f}=",embeded_records) + end + end + if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].class_name == "MemberProfile" + if @records_all["#{f}_ids"].nil? + new_object.send("#{f}_id=",clone_target.send("#{f}_id")) + else + new_object.send("#{f}_id=",(@records_all["#{f}_ids"][clone_target.send("#{f}_id")])) + end + elsif clone_target.relations[f].macro == :has_one + next if (self.except_clone_relations.to_s.include?(f) rescue false) + need_clone_relation = clone_target.send(f) + clone_relation = new_object.send(f) + clone_relation = need_clone_relation.dup if clone_relation.nil? + initialize_fields.each do |f| + clone_relation.send("#{f}=",nil) if clone_relation.fields.keys.include?(f) + end + check_fields = clone_relation.fields.except(initialize_fields) + check_fields.keys.each do |f| + if (clone_relation.send(f).class.to_s.match(/uploader/i) rescue false) + if clone_relation[f].blank? && (clone_relation.send(f).file.nil? rescue true) + clone_relation[f] = r[f] + source_filepath = r.send(f).file.file + if @clone_mode + dest_filepath = clone_relation.send(f).file.file + FileUtils.mkdir_p(File.dirname(dest_filepath)) + FileUtils.cp(source_filepath,dest_filepath) + end + elsif (clone_relation.send(f).file rescue nil) + clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s) + end + file_flag = true + end + end + new_object.send("#{f}=",clone_relation) + elsif clone_target.relations[f].macro == :has_many + next if (self.except_clone_relations.to_s.include?(f) rescue false) + clone_relations = [] + need_clone_relations = clone_target.send(f).asc(:_id).to_a + file_flag = false + need_clone_relations.each_with_index do |r,i| + clone_relation = new_object.send(f)[i] + clone_relation = r.dup if clone_relation.nil? + initialize_fields.each do |f| + clone_relation.send("#{f}=",nil) if clone_relation.fields.keys.include?(f) + end + check_fields = clone_relation.fields.except(initialize_fields) + check_fields.keys.each do |f| + if (clone_relation.send(f).class.to_s.match(/uploader/i) rescue false) + if clone_relation[f].blank? && (clone_relation.send(f).file.nil? rescue true) + clone_relation[f] = r[f] + source_filepath = r.send(f).file.file + if @clone_mode + dest_filepath = clone_relation.send(f).file.file + FileUtils.mkdir_p(File.dirname(dest_filepath)) + FileUtils.cp(source_filepath,dest_filepath) + end + elsif (clone_relation.send(f).file rescue nil) + clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s) + end + file_flag = true + end + end + clone_relations << clone_relation + end + if !no_dup_flag || (no_dup_flag && file_flag) + new_object_relations = new_object.send(f).to_a + if new_object_relations.count != 0 + if clone_relations.count > new_object_relations.count + clone_relations = clone_relations[0...new_object_relations.count] + else + clone_relations = clone_relations.concat(new_object.send(f)[clone_relations.count...new_object_relations.count]) + end + new_object.send("#{f}=",clone_relations) + else + new_object.send("#{f}=",clone_relations) + end + end + count_array = (0...new_object.send(f).to_a.count).to_a + count_array.each do |i| + clone_new_for_object(new_object.send(f)[i],need_clone_relations[i],true) + end + end + end + new_object.copy_id = clone_target.id if new_object.fields.keys.include?("copy_id") + return new_object, clone_target + end + end protected def check_deadline diff --git a/app/models/survey_question.rb b/app/models/survey_question.rb index 0a15376..031f48e 100644 --- a/app/models/survey_question.rb +++ b/app/models/survey_question.rb @@ -10,6 +10,7 @@ class SurveyQuestion DoubleLevelOption = 7 include Mongoid::Document + include Mongoid::Attributes::Dynamic field :title, :localize => true field :description, :localize => true diff --git a/app/models/survey_question_radiogroup.rb b/app/models/survey_question_radiogroup.rb index bc755fc..f3fd3a9 100644 --- a/app/models/survey_question_radiogroup.rb +++ b/app/models/survey_question_radiogroup.rb @@ -1,5 +1,6 @@ class SurveyQuestionRadiogroup include Mongoid::Document + include Mongoid::Attributes::Dynamic field :name, :localize => true