简体   繁体   中英

How can I render a partial with a new instance of my object from the create action of that object's controller in Rails?

I have a series of hard-coded questions in my app. A SaleQualifier picks up each question, and depending on the Answer (SaleQualifier has_one Answer) the app decides which subsequent question to present to the User next.

The SaleQualifier belongs_to SalesOpportunity - and the question and answer field are both rendered inside a partial on my SalesOpportunity show page. This works fine when I'm reloading the entire page every time the question is answered, but I want to use a remote: true link and create.js.erb file in the SaleQualifier view to render the next partial without a full page refresh.

Sales Opportunity Controller:

  # GET /sales_opportunities/1
# GET /sales_opportunities/1.json
def show
 @sales_opportunity = SalesOpportunity.includes(:company, :user, :timeline_events, :sale_contacts, :swots, :sale_competitors).find(params[:id])
 @sale_qualifier = SaleQualifier.new(sales_opportunity_id: params[@sales_opportunity.id])
  @answer = @sale_qualifier.build_answer
 @question = find_current_question
end

As you can see I'm setting up a new SaleQualifier here, building an answer for it, and finding the relevant question using the method below:

 def find_current_question
  question = Question.find(@sales_opportunity.next_question)
  return question
end

The partial is as follows (I've tried passing locals, but this isn't working as I think the issue is in the create action of the SaleQualifier controller):

<div class="panel panel-default">
 <%= form_for(@sale_qualifier, :html => {role: :form, 'data-model' => 'sale_qualifier'}, remote: true) do |f| %>
  <% if @sale_qualifier.errors.any? %>
   <div id="error_explanation">
    <h2><%= pluralize(@sale_qualifier.errors.count, "error") %> prohibited this answer from being saved:</h2>
    <ul>
    <% @sale_qualifier.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
    </ul>
  </div>
<% end %>
<div class="panel-body">
  <div class="col-sm-6">
    <h2><%= @question.question_text %></h2>
  </div>
  <div class="col-sm-6">
    <div class="form-group">
      <%= f.hidden_field :sales_opportunity_id, :value => @sales_opportunity.id %>
    </div>
    <div class="form-group">
      <%= f.hidden_field :question_id, :value => @question.id %>
    </div>
    <%= f.fields_for :answer do |answer| %>
      <% if @question.answer_type == 'Text Field' %>
        <%= answer.text_area :answer_text, :placeholder => "Enter your answer" %>
      <% end %>
      <% if @question.answer_type == 'Datetime' %>
      <div class='input-group date' id='datetimepicker' data-date-format="YY.MM.DD">
        <%= answer.text_field :answer_text, class: "form-control", data: { date_format: 'YYYY/MM/DD' }, :placeholder => "YYYY/MM/DD" %>
        <span class="input-group-addon">
          <span class="glyphicon glyphicon-calendar"></span>
         </span>
      </div>
        <% end %>
        <% if @question.answer_type == 'Boolean' %>
          <%= answer.select :answer_text, [['Yes', true], ['No', false]] %>
        <% end %>
        <% if @question.answer_type == 'Update' %>
          <%= answer.hidden_field :answer_text, :value => "Updated" %>
        <% end %>
    <% end %>
      <% if @question.answer_type == 'Update' %>
        <div class="actions">
          <%= f.submit "Done", class: "btn btn-large btn-success"%>
        </div>
      <% else %>
        <div class="actions">
          <%= f.submit "Submit", class: "btn btn-large btn-success"%>
        </div>
      <% end %>
    <% end %>
  </div>
 </div>
</div>

Upon submission of this a bunch of code runs behind the scenes to update the SalesOpportunity so the correct next question is rendered.

The create action of my SaleQualifier Controller is as-follows:

  def create
   @sale_qualifier = SaleQualifier.new(sale_qualifier_params)
   @sales_opportunity = @sale_qualifier.sales_opportunity

   respond_to do |format|
    if @sale_qualifier.save
     format.html { redirect_to @sales_opportunity, notice: 'Sale qualifier was successfully created.' }
     format.json { render :show, status: :created, location: @sale_qualifier }
     format.js
    else
     format.html { render :new }
     format.json { render json: @sale_qualifier.errors, status: :unprocessable_entity }
    end
  end
end

I believe my issue stems here - because the partial is expecting to see @sale_qualifier as per the definitions set up in my SalesOpportunity show action, but instead @sale_qualifier here is referring to the newly saved instance of that model. As such when I try to use this with remote: true set, I get the following error:

ActionView::Template::Error (undefined method `question_text' for nil:NilClass):
12:     <% end %>
13:     <div class="panel-body">
14:       <div class="col-sm-6">
15:         <h2><%= @question.question_text %></h2>
16:       </div>
17:       <div class="col-sm-6">
18:         <div class="form-group">
app/views/sale_qualifiers/_qualify.html.erb:15:in `block in _app_views_sale_qualifiers__qualify_html_erb__3308770490925429645_70100598754380'
app/views/sale_qualifiers/_qualify.html.erb:2:in `_app_views_sale_qualifiers__qualify_html_erb__3308770490925429645_70100598754380'
app/views/sale_qualifiers/create.js.erb:2:in `_app_views_sale_qualifiers_create_js_erb__2206693572750561934_70100598786040'
app/controllers/sale_qualifiers_controller.rb:32:in `create'

The create.js.erb code:

//update the sale qualifier div with the next question
$('#sale_qualifier_div').html("<%= escape_javascript(render :partial => 'sale_qualifiers/qualify', :locals => { :sale_qualifier => @sale_qualifier, :answer => @answer, :question => @question} )%>");

Is there a way I can pass these variables to this partial?

I've managed to solve this (but would appreciate anyone who can tell me why this is a bad idea/give me a better option) through using a block passed to the format.js action where I reset these instance variables:

    format.js {
      @sales_opportunity = SalesOpportunity.find_by(id: session[:sales_opportunity_id])
      @sale_qualifier = SaleQualifier.new(sales_opportunity_id: params[@sales_opportunity.id])
      @answer = @sale_qualifier.build_answer
      @question = Question.find(@sales_opportunity.next_question)
    }

This works, but it feels ugly/smelly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM