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!
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.