diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 8ef2500..8b762fd 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -9,42 +9,44 @@ ans_params = params[:answer] plan_id = ans_params[:plan_id] + phase_id = ans_params[:phase_id] user_id = ans_params[:user_id] + lock_version = ans_params[:lock_version] question_id = ans_params[:question_id] + @question = Question.find(question_id); @answer = Answer.find_by( plan_id: plan_id, user_id: user_id, question_id: question_id) + + @old_answer = nil + if @answer.nil? + logger.debug "didn't find answer so creating a new one" @answer = Answer.new(params[:answer]) + authorize @answer + @answer.save + else + # if you do the obvious clone here it will overwrite the old_answer text + # in the next line + #@old_answer = @answer.clone + @old_answer = Marshal::load(Marshal.dump(@answer)) + @answer.text = params["answer-text-#{@answer.question_id}".to_sym] + authorize @answer + @answer.update(params[:answer]) end - authorize @answer + respond_to do |format| + # pass new lock_version back to the client or they'll never save again + @lock_version = @answer.lock_version + @old_answer = nil + format.js {} + end -puts params.inspect - - @answer.text = params["answer-text-#{@answer.question_id}".to_sym] - - #TODO: check for optimistic locking - - # Is this validation necessary? -# if (@answer.question.question_format.title == I18n.t("helpers.checkbox") || -# @answer.question.question_format.title == I18n.t("helpers.multi_select_box") || -# @answer.question.question_format.title == I18n.t("helpers.radio_buttons") || -# @answer.question.question_format.title == I18n.t("helpers.dropdown")) then -# if (old_answer.nil? && @answer.option_ids.count > 0) || ((!old_answer.nil?) && (old_answer.option_ids - @answer.option_ids).count != 0 && (@answer.option_ids - old_answer.option_ids).count != 0) then -# proceed = true -# end -# end - -# if proceed - if @answer.save - redirect_to :back, status: :found, notice: I18n.t('helpers.project.answer_recorded') - else - redirect_to :back, notice: I18n.t('helpers.project.answer_error') - end -# else -# redirect_to :back, notice: I18n.t('helpers.project.answer_no_change') -# end - end + rescue ActiveRecord::StaleObjectError + @lock_version = @old_answer.lock_version + respond_to do |format| + format.js {} + end + end end diff --git a/app/models/answer.rb b/app/models/answer.rb index 35e0c2d..b84aeba 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -13,7 +13,7 @@ ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 - attr_accessible :text, :plan_id, :question_id, :user_id, :question_option_ids, + attr_accessible :text, :plan_id, :lock_version, :question_id, :user_id, :question_option_ids, :question, :user, :plan, :question_options, :notes, :note_ids, :as => [:default, :admin] diff --git a/app/models/question.rb b/app/models/question.rb index 61eddd1..c36aaef 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -44,6 +44,12 @@ "#{text}" end + + def isOptionBased? + format = self.question_format + return format.option_based + end + ## # deep copy the given question and all it's associations # diff --git a/app/models/question_format.rb b/app/models/question_format.rb index 7f1a900..17c3123 100644 --- a/app/models/question_format.rb +++ b/app/models/question_format.rb @@ -1,4 +1,5 @@ class QuestionFormat < ActiveRecord::Base + include FlagShihTzu ## # Associations @@ -11,6 +12,17 @@ # -relies on protected_attributes gem as syntax depricated in rails 4.2 attr_accessible :title, :description, :option_based, :questions, :as => [:default, :admin] + ## + # Define Bit Field Values so we can test a format without doing string comps + # Column type + has_flags 1 => :textarea, + 2 => :textfield, + 3 => :radiobuttons, + 4 => :checkbox, + 5 => :dropdown, + 6 => :multiselectbox, + 7 => :date, + column: 'formattype' # EVALUATE CLASS AND INSTANCE METHODS BELOW # @@ -25,4 +37,4 @@ "#{title}" end -end \ No newline at end of file +end diff --git a/app/views/answers/update.js.erb b/app/views/answers/update.js.erb new file mode 100644 index 0000000..c26a623 --- /dev/null +++ b/app/views/answers/update.js.erb @@ -0,0 +1,24 @@ +console.log("Answer update called"); + +// after saving the answer (and possibly getting a conflict) +// set the message div about the answer. +// On success this will be "" on error it will be the +// conflicting answer + +//$("#answer_notice").html("<%= raw @message %>"); + +<%if @message %> + $("#answer_notice-<%=@question.id%>").html(<%= @message %>) %>"); +<% end %> + +<% if @old_answer %> + $("#answer_notice_<%=@question.id%>").html("<%= escape_javascript(render partial: '/phases/answer', locals: { question: @question, answer: @old_answer}) %>"); +<% else %> + $("#answer_notice_<%=@question.id%>").html(""); +<% end %> + +// have to update the lock_version on success or failure +// so that the next save can work. If you don't do +// this it will fail forever. + +$("#answer_lock_version").val(<%= @lock_version %>); diff --git a/app/views/phases/_answer.html.erb b/app/views/phases/_answer.html.erb new file mode 100644 index 0000000..d3563f9 --- /dev/null +++ b/app/views/phases/_answer.html.erb @@ -0,0 +1,77 @@ + + +<% qformat = question.question_format %> + + + +

While you were editing <%= answer.user.name %> saved the following answer:

+ +<%= semantic_form_for answer, :url => {:controller => :answers, :action => :update }, :remote => true do |af| %> + <%= af.inputs do %> + + + <% if question.isOptionBased? %> + <% options = question.options.order("number") %> + + + <% if qformat.checkbox? %> + <%= af.input :options, + :as => :check_boxes, + :collection => options, + :label => false, + :input_html => { :disabled => :true } + %> + <% elsif qformat.multiselectbox? %> + <%= af.input :options, + :as => :select, + :collection => options, + :label => false, + :input_html => { :multiple => true , :disabled => :true } %> + <% elsif qformat.radiobuttons %> +
    + <% options.each do |op| %> +
  1. + <% checked = (answer.option_ids[0] == op.id) %> + <%= af.radio_button :option_ids, op.id, :checked => checked, id: "answer_option_ids_#{op.id}"%> + <%= raw op.text %> +
  2. + <% end %> +
+ <% elsif qformat.dropdown? %> + <%= af.input :options, + :as => :select, + :collection => options, + :label => false, + :input_html => { :multiple => false, :disabled => :true } + %> + <% end %> + + + <% if question.option_comment_display %> + <%= label_tag("answer-text-Ans#{question.id}".to_sym, t("helpers.comment")) %> + <%= text_area_tag("answer-text-Ans#{question.id}".to_sym, answer.text, class: "tinymce") %> + <%end%> + <% end %> + + <% if qformat.textfield? %> + <%= text_field_tag("answer-text-Ans#{question.id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> + <% elsif qformat.textarea? %> + <%= text_area_tag("answer-text-Ans#{question["id"]}".to_sym, strip_tags(answer.text), class: "tinymce") %> + <% end %> + + <% end %> +<% end %> + +

Combine with your answer and save.

+ + diff --git a/app/views/phases/_answer_form.html.erb b/app/views/phases/_answer_form.html.erb index 74ae43a..2eed300 100644 --- a/app/views/phases/_answer_form.html.erb +++ b/app/views/phases/_answer_form.html.erb @@ -8,7 +8,6 @@
<% - q_format = question["question_format"] answer = nil answer_obj = nil if question.has_key?("answers") @@ -17,15 +16,18 @@ else answer_obj = Answer.new end - question_obj = Question.find(question["id"]) + question_id = question["id"] + question_obj = Question.find(question_id) + q_format = question_obj.question_format %> -
" class="question-form"> - <%= semantic_form_for answer_obj, :url => {:controller => :answers, :action => :update }, :html=>{:method=>:put}, :remote => true do |f| %> +
+ <%= semantic_form_for answer_obj, :url => {:controller => :answers, :action => :update }, :remote => true do |f| %> <%= f.inputs do %> <%= f.input :plan_id, :as => :hidden, :input_html => { :value => @plan_data["id"] } %> <%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %> - <%= f.input :question_id, :as => :hidden, :input_html => { :value => question["id"], :class => "question_id" } %> + <%= f.input :question_id, :as => :hidden, :input_html => { :value => question_id, :class => "question_id" } %> + <%= f.hidden_field :lock_version %> @@ -51,16 +53,19 @@
<% end %> + +
+ - <% if [ @checkbox, @multi, @radio, @dropdown ].include?( q_format["id"] ) %> + <% if question_obj.isOptionBased? %> <% options = question.options.order("number") %> - <% if q_format.id == @checkbox %> + <% if q_format.checkbox? %> <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, :input_html => { :id => "options-#{question.id}" } %> - <% elsif q_format.id == @multi %> + <% elsif q_format.multiselectbox? %> <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true , :id => "options-#{question.id}" } %> - <% elsif q_format.id == @radio %> + <% elsif q_format.radiobuttons? %>
    <% options.each do |op| %>
  1. @@ -72,7 +77,7 @@ <%= raw op.text %>
  2. <% end %>
- <% elsif q_format.id == @dropdown %> + <% elsif q_format.dropdown? %> <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :id => "options-#{question.id}" } %> <% end %> @@ -84,10 +89,10 @@ <%end%> <% end %> - <% if q_format["id"] == @textfield %> - <%= text_field_tag("answer-text-#{question.id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> - <% elsif q_format["id"] == @textarea %> - <%= text_area_tag("answer-text-#{question["id"]}".to_sym, answer_obj.text, class: "tinymce") %> + <% if q_format.textfield? %> + <%= text_field_tag("answer-text-#{question_id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> + <% elsif q_format.textarea? %> + <%= text_area_tag("answer-text-#{question_id}".to_sym, answer_obj.text, class: "tinymce") %> <% end %> <% end %> @@ -95,26 +100,26 @@ <%= f.actions do %> <%= f.action :submit, :label => t("helpers.save"), :button_html => { :class => "btn btn-primary"} %> -
  • " class="saving-message" style="display:none;"><%= t("helpers.saving")%>
  • + <% end %> <% end %>
    <% if answer.nil? || !answer.has_key?("created_at") || answer["created_at"].nil? %> - -status" class="label label-warning answer-status"><%= t("helpers.notanswered") %> + <%= t("helpers.notanswered") %> <% else %> - -status" class="label label-info answer-status"><%= t("helpers.answered_by")%><%= answer_obj.created_at %><%= t("helpers.answered_by_part2")%><%= answer_obj.user.name %> + <%= t("helpers.answered_by")%><%= answer_obj.created_at %><%= t("helpers.answered_by_part2")%><%= answer_obj.user.name %> <% end %>
    --unsaved" class="label label-inverse answer-unsaved" style="display:none;"><%= t("helpers.unsaved") %> +
    -
    " class="question_right_column_nav"> +
    <% comments = answer_obj.notes.all %> - <%= hidden_field_tag :question_id, question["id"], :class => "question_id" %> + <%= hidden_field_tag :question_id, question_id, :class => "question_id" %>