Search code examples
ruby-on-railsruby-on-rails-4form-forhidden-field

Why is my Rails hidden_field not picking up any value when all other fields work fine?


I have a model for a "timeline_event" which belongs_to a sales_opportunity. For example it could be "call the prospect" or similar, with a due_date, activity_details (optional), and a checkbox to say whether it's complete or not. This works fine. I can add new timeline_events to the database via a modal on the sales_opportunity page, which also works fine. However when I try to edit the timeline_event (via the timeline_events edit controller action) the hidden_field for sales_opportunity_id refuses to pick up the value (it has no value whatsoever). Even when I try to force a value:

<%= f.hidden_field :sales_opportunity_id, :value => @sales_opportunity.id %>

It won't add any value to the hidden_field. I've tried moving the field around within the form group, but nothing seems to work. I have other forms that are similar in my model that work fine, but for some reason this isn't working - can anyone help please?

My Form:

<%= form_for(@timeline_event, :html => {:class => "form-horizontal"}) do |f| %>
      <div class="form-group">
        <%= f.hidden_field :sales_opportunity_id %>
        <%= f.label :activity, :class => "col-md-4 control-label" %>
        <div class ="col-md-8">
          <%= f.text_field :activity, :placeholder => "Enter activity details" %>
        </div>
      </div>
            <div class="form-group">
               <%= f.label :due_date, :class => "col-md-4 control-label" %>
            <div class ="col-md-8">
             <div class='input-group date' id='datetimepicker' data-date-format="YY.MM.DD">
                 <%= f.text_field :due_date, 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>
           </div>
         </div>
        <div class="form-group">
          <%= f.label :event_notes, 'Activity Details', :class => "col-md-4 control-label" %>
          <div class ="col-md-8">
            <%= f.text_area(:event_notes, :placeholder => "Put any notes about the activity here") %>
          </div>
        </div>
        <div class="col-md-6 col-md-offset-4">
          <div class="checkbox input">
              <label>
              <%= f.check_box :completed %> Task Completed?
              </label>
           </div>
           <br>
         </div>
       <%= @sales_opportunity.id %>
       <%= f.submit "Save", class: "btn btn-large btn-success" %>
      <% end %>

*Note - I include the line <%= @sales_opportunity.id %> here and this does output the correct sales_opportunity_id for the timeline_event. All other fields (activity, due_date, completed) are populated with the information of the timeline_event I'm trying to edit.

Timeline_Events_Controller:

class TimelineEventsController < ApplicationController
  before_action :set_timeline_event, only: [:show, :edit, :update, :destroy]
  before_action :signed_in_user, only: [:edit, :update, :show, :index]
  before_action :correct_org,   only: [:edit, :update, :show, :index]

  # GET /timeline_events
  # GET /timeline_events.json
  def index
    @timeline_events = TimelineEvent.all
  end

  # GET /timeline_events/1
  # GET /timeline_events/1.json
  def show
  end

  # GET /timeline_events/new
  def new
    @timeline_event = TimelineEvent.new(sales_opportunity_id: params[:sales_opportunity_id])
  end

  # GET /timeline_events/1/edit
  def edit
    @timeline_event = TimelineEvent.find(params[:id])
    @sales_opportunity = @timeline_event.sales_opportunity
  end

  # POST /timeline_events
  # POST /timeline_events.json
  def create
    @timeline_event = TimelineEvent.new(timeline_event_params)
    @sales_opportunity = @timeline_event.sales_opportunity

respond_to do |format|
  if @timeline_event.save
    format.html { redirect_to @timeline_event.sales_opportunity, :flash => {:success =>  'Timeline event was successfully created.'} }
    format.json { render :show, status: :created, location: @timeline_event }
    format.js
  else
    format.html { render :new }
    format.json { render json: @timeline_event.errors, status: :unprocessable_entity }
    format.js { render json: @sales_opportunity.errors, status: :unprocessable_entity }
  end
 end
end

  # PATCH/PUT /timeline_events/1
  # PATCH/PUT /timeline_events/1.json
  def update
respond_to do |format|
  if @timeline_event.update(timeline_event_params)
    format.html { redirect_to @timeline_event.sales_opportunity, :flash => {:success =>  'Timeline event was successfully updated.'} }
    format.json { render :show, status: :ok, location: @timeline_event }
  else
    format.html { render :edit }
    format.json { render json: @timeline_event.errors, status: :unprocessable_entity }
  end
 end
end

  # DELETE /timeline_events/1
  # DELETE /timeline_events/1.json
  def destroy
    @timeline_event.destroy
     respond_to do |format|
      format.html { redirect_to timeline_events_url, :flash => {:success =>  'Timeline event was successfully destroyed.'} }
      format.json { head :no_content }
    end
  end

private
 # Use callbacks to share common setup or constraints between actions.
 def set_timeline_event
  @timeline_event = TimelineEvent.find(params[:id])
 end


def timeline_event_params
  params.require(:timeline_event).permit(:sales_opportunity_id, :due_date, :activity, :completed, :event_notes)
end

#before filters
 def signed_in_user
 unless signed_in?
    store_location
   redirect_to signin_url, notice: "Please sign in." unless signed_in?
   end
 end

def correct_org
  timeline_org = @timeline_event.sales_opportunity.user.organization
  @user = current_user
  if @user.organization_id == timeline_org.id
  else
  redirect_to root_url, notice: "You are not permitted to visit that page. Please create an account or sign in"
  end
 end
end

My timeline_event model:

class TimelineEvent < ActiveRecord::Base
belongs_to :sales_opportunity
validates :activity, presence: true 
validates :due_date, presence: true
validates :sales_opportunity_id, presence: true
end

I can only imagine this is some syntax error or other stupid error on my part, because I just can't see anything wrong with the code (it's identical to all other forms on my site). Can anyone spot where I'm going wrong here please?

Thanks!


Solution

  • I disagree with @smathy as you indeed can explicitly pass a value to a hidden_field tag like you have done.

    However, that's not even necessary because you are doing a circular assignment. By that I mean you are declaring @sales_opportunity and assigning it the value of @timeline_event.sales_opportunity in the edit action of your controller.

    You then go into the view and try to assign @timeline_event.sales_opportunity back to @sales_opportunity. That's circular logic.

    If the sales_opportunity for the timeline_event you are editing is already present, and you aren't wanting to allow the user to edit it, why include it in the form at all? Delete the @sales_opportunity instance variable from the edit action in the controller, and just remove the hidden field entirely from the view.

    See if doing that makes it work as desired.