I'm trying to use the Tempus Dominus Datetime picker in my app. Everything seems to work fine, but when I try to convert the submitted string into a datetime object in my controller, I get a TypeError (no implicit conversion of nil into String). I've also tried to puts the parameters into the logs, but get a blank line. The odd thing is, during the submission of the form, the parameters do seem to be present.
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", >"authenticity_token"=>"yuP08tdkavDAzcbJImZXeL0EZ1dp6D13dnLyW/lU+frPVej0tiUmavI>0GKvs66z7+ca2GynI1WWs2d5aSJX5zA==", "event"=>{"title"=>"aaaaa", >"game"=>"bbbb", "start_time"=>"02/21/2020 1:26 PM", "end_time"=>"02/28/2020 >10:46 PM", "description"=>"sasasa"}, "button"=>""}
Here's all relevant code.
Controller:
class EventsController < ApplicationController
def new
#event = Event.new
end
def create
#user = current_user
if #user
#user.events.create(title: params[:title], game: params[:game],
start_time: time_parse(params[:start_time]),
end_time: time_parse(params[:start_time]),
description: params[:description])
end
end
private
def event_params
params.require(:event).permit(:title, :game, :start_time,:end_time, :description)
end
def time_parse(time)
DateTime.strptime(time, '%m/%d/%Y %M:%S %p')
end
end
View:
<div class="col-lg-6">
<%= form_for #event, url: events_path do |form| %>
<div class="form-row">
<div class="col-md-6 form-group">
<%= form.text_field :title, class: "form-control", placeholder: "Party Title" %>
</div>
<div class="col-md-6 form-group">
<%= form.text_field :game, class: "form-control", placeholder: "Game" %>
</div>
</div>
<div class="row">
<div class='col-md-6'>
<div class='form-group'>
<%= form.label :start_time, 'Start Date and Time', class: 'control-label' %><br>
<div class="input-group date" id="datetimepicker1" data-target-input="nearest">
<%= form.text_field(:start_time,
value: form.object.start_time ? form.object.start_time.strftime('%B %d, %Y %I:%M %p') : nil,
class: "form-control datetimepicker-input", data: {target:"#datetimepicker1"}) %>
<div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fas fa-calendar-plus"></i></div>
</div>
</div>
</div>
</div>
<div class='col-md-6'>
<div class='form-group'>
<%= form.label :end_time, 'End Date and Time', class: 'control-label' %><br>
<div class="input-group date" id="datetimepicker2" data-target-input="nearest">
<%= form.text_field(:end_time,
value: form.object.end_time ? form.object.end_time.strftime('%B %d, %Y %I:%M %p') : nil,
class: "form-control datetimepicker-input", data: {target:"#datetimepicker2"}) %>
<div class="input-group-append" data-target="#datetimepicker2" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fas fa-calendar-plus"></i></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 form-group">
</div>
<%= form.text_area :description, class: "form-control", size: "24x6", placeholder: "Describe your meetup"%>
</div>
<div class="text-center "><%= form.button "Sign up", class: "sub-but" %></div>
<% end %>
</div>
Javascript for view:
$('#datetimepicker1').datetimepicker({
format: 'MMMM D, YYYY h:mm A',
stepping: 15,
minDate: Date(),
maxDate: new Date(Date.now() + (365 * 24 * 60 * 60 * 1000)),
sideBySide: true,
icons: {
up: 'fas fa-arrow-up',
down: 'fas fa-arrow-down',
previous: 'fas fa-chevron-left',
next: 'fas fa-chevron-right',
close: 'fas fa-times'
},
buttons: {showClose: true }
});
$('#datetimepicker2').datetimepicker({
format: 'MMMM D, YYYY h:mm A',
stepping: 15,
useCurrent: false,
sideBySide: true,
icons: {
up: 'fas fa-arrow-up',
down: 'fas fa-arrow-down',
previous: 'fas fa-chevron-left',
next: 'fas fa-chevron-right',
close: 'fas fa-times'
},
buttons: {showClose: true }
});
$("#datetimepicker1").on("change.datetimepicker", function (e) {
$('#datetimepicker2').datetimepicker('minDate', e.date);
console.log(e.date);
});
$("#datetimepicker2").on("change.datetimepicker", function (e) {
$('#datetimepicker1').datetimepicker('maxDate', e.date);
});
I think you are not linking to the params correctly, also I noticed you have the :start_time going into both in your code above, I assume that is a typo so I changed it in my answer. If it isn't a typo then keep that as is.
...
start_time: time_parse(params[:event][:start_time]),
end_time: time_parse(params[:event][:end_time]),
...
Related
within my view form, I currently have this code:
<div class="panel panel-default">
<div class= "panel-body">
<%= form_for #meal_plan, url: new_meal_plan_path, method: "GET", html: { class: "form-inline" } do |form| %>
<div class="form_group">
<%= form.label :start_date %>
<%= form.text_field :start_date, type: "date", class: "form-control" %>
</div>
<div class="form_group">
<%= form.label :end_date %>
<%= form.text_field :end_date, type: "date", class: "form-control" %>
</div>
<div class="form-group action">
<%= form.submit "Generate Plan", class: "btn btn-default"%>
</div>
<% end %>
</div>
</div>
That takes a start date and an end date input for a meal plan. In the new method within the meal_plan_controller, I have:
def new
puts params[:start_date]
puts params[:end_date]
#meal_plan = current_user.meal_plans.build(
start_date: params[:start_date] || Date.today,
end_date: params[:end_date] || 6.days.from_now.to_date,
)
#meal_plan.build_meals
end
In the puts statements that I wrote to debug, :start_date and :end_date contains only the default dates, so my guess is that the dates are not saving when the user hits submit, but I can't figure out why.
Updating simple_form works fine but when I reload the page, it renders all the inputs as disabled. Any ideas? I can't find anything in the documentation that says what causes it to do this automatically. Thanks
the simple form.
<%= simple_form_for #product_campaign, url: update_completion_criteria_rules_partner_product_product_campaign_path(partner_id: #partner.id, product_id: #product.id, id: #product_campaign.id), remote: true, html: { id: "product-campaign-completion-criteria-rules"} do |f| %>
<div class="">
<%= f.simple_fields_for :completion_criteria_rules, f.object.completion_criteria_rules.order(:created_at) do |complete_criteria_rule| %>
<%= render 'completion_criteria_rule_fields', :f => complete_criteria_rule %>
<% end %>
<%= link_to_add_association "Add Completion Criteria Rule", f, :completion_criteria_rules, class: "btn btn-info float-left mt-10", id: "add-completion-criteria-rule", data: { } %>
<button type="submit" class="btn btn-info float-right mt-10" id="update-product-campaign-form" ><span id="save-journey-button-text">Save Changes</span></button>
</div>
<% end %>
completion_criteria_rule_fields partial
<div class="form-row">
<div class="form-group col-md-6">
<%= f.input :events, collection: CompletionCriteriaRule::EVENTS_OPTIONS, label: 'Choose Events', include_blank: false, input_html: { class: "form-control form-field-type", "data-provide": "selectpicker", multiple: true } %>
</div>
<div class="form-group col-md-6">
<%= f.input :actions, collection: [['Add Campaign', 'add_campaign']], label: 'Choose Action', input_html: { class: "form-control form-field-type actions-dropdown", "data-provide": "selectpicker", multiple: true } %>
</div>
</div>
<div class="form-row add-campaign-dropdown-wrapper" <% unless f.object.actions&.include?('add_campaign') %>style="display:none;<% end %>">
<div class="form-group col-md-6">
<%= f.input :transition_campaign_id, collection: #product_campaign.product.product_campaigns.where.not(id: #product_campaign.id).published.map{|k,v| [k.name.titleize, k.id]}, label: 'Select Campaign To Add', input_html: { class: "form-control form-field-type", "data-provide": "selectpicker" } %>
</div>
<div class="form-group col-md-6">
<label>Campaign Start Delay</label>
<div class="input-group">
<%= f.input_field :transition_campaign_delay, class: "form-control form-field-type" %>
<span class="input-group-addon">days</span>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<span class="float-right">
<%= link_to_remove_association 'Remove Rule', f, class: "btn btn-danger btn-xs" %><br>
</span>
</div>
</div>
<div class="divider"></div>
</div>
completion_criteria_rule.rb
class CompletionCriteriaRule < ApplicationRecord
EVENTS_OPTIONS = [["Appointment Booked", "appointment.booked"], ["Appointment Attended", "appointment.attended"], ["Appointment Cancelled", "appointment.cancelled"], ["Lifecycle Changed to Client", "lifecycle.client"], ["Lifecycle Changed to Lead", "lifecycle.lead"], ["Lifecycle Changed to Former Client", "lifecycle.former_client"], ["Lifecycle Changed to None", "lifecycle.none"]].freeze
belongs_to :product_campaign
belongs_to :transition_campaign, class_name: 'ProductCampaign', foreign_key: 'transition_campaign_id', optional: true
validates :product_campaign, :events, :actions, presence: true
validates :transition_campaign, :transition_campaign_delay, presence: true, if: -> { actions&.include? 'add_campaign' }
before_save :reject_blank_events
before_save :reject_blank_actions
def reject_blank_events
events.reject!(&:blank?)
end
def reject_blank_actions
actions.reject!(&:blank?)
end
end
Found out that I had some js that was disabling form inputs with a certain class that was disabling the inputs after page load. All working now.
Rails 6.0.3
I am using a form to schedule meetings.
It is being used for both single time meetings that span over several days (with start_time and end_time) and tasks that last only one day.
For singular day meetings, I need the end_time to be set to the same value as start_time, without user selecting it.
I have tried many things in the controller, but can't work it out.
How would you go about this.
Thanks for the help
<div class="border border-grey-light rounded" style ="padding: 10px;">
<%= form_with(model: meeting, local: true, :html => {:id => "flatpickr-form-single"} ) do |form| %>
<div class="mb-6">
<%= form.label :name, class: 'label' %>
<%= form.text_field :name, required: true, class: 'form-control', placeholder: "Task name" %>
</div>
<div class="mb-6">
<%= form.label :body %>
<%= form.rich_text_area :body, class: 'form-control' %>
</div>
<div class="start_time_result mb-6" style ="width: 30vw;">
<%= form.label :start_time, class: 'label' %>
<div class="flex items-center justify-between max-w-md">
<%= form.text_field :start_time, data: { behavior: "flatpickr" }, placeholder: "Date and time select ...", class: "form-control" %>
</div>
</div>
<div class=" field" style ="width: 30vw;">
<%= form.label :end_time, class: 'label' %>
<div class="end_time_result flex items-center justify-between max-w-md" >
<%= form.text_field :end_time, data: { behavior: "flatpickr" }, placeholder: "Date and time select ...", class: "form-control required" %>
</div>
</div>
<%= form.submit class: "btn btn-primary text-base py-1.5 px-5", value: "Confirm" %>
<% end %>
</div>
<script>
const selectElement = document.querySelector('.start_time_result');
selectElement.addEventListener('change', (event) => {
const end_time_result = document.querySelector('.end_time_result');
end_time_result.textContent = `${event.target.value}`;
});
</script>
You can add a before_action in the controller and set the end_time parameter value to the same as the start_time from there.
Sorry for the messy post, my first time posting. I have been trying to get this collection submit to work, but every time I press create report button I have it goes back to the screen and puts out Unpermitted parameter: :hero_id in the rails server terminal.
Model
class Report < ApplicationRecord
validates :subject, presence: true, length: { minimum: 6, maximum: 100 }
validates :description, presence: true, length: { minimum: 10, maximum: 300 }
belongs_to :requester
has_and_belongs_to_many :heros
end
View/Form
<div class="container">
<div class="row justify-content-center">
<div class="col-10">
<% if #report.errors.any? %>
<h2>The following errors prevented the article from being saved</h2>
<ul>
<% #report.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= form_with(model: #report, class: "shadow p-3 mb-3 bg-dark rounded", local: true) do |f| %>
<div class="form-group row">
<%= f.label :subject, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= f.text_field :subject, class: "form-control shadow rounded", placeholder: "Subject of Report" %>
</div>
</div>
<div class="form-group row">
<%= f.label :description, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= f.text_area :description, rows: 10, class: "form-control shadow rounded", placeholder: "Description of Issue" %>
</div>
</div>
<div class="form-group row">
<%= f.label :hero, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= f.collection_select(:hero_ids, Hero.all, :id, :hero_name, {prompt: "Select a Hero"}, {:required => true}) %>
</div>
</div>
<div class="btn-toolbar p-2 mb-2 row justify-content-center">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>
</div>
<div class="mb-3">
<%= link_to '[ Cancel and return to reports listing ]', reports_path, class: "text-info" %>
</div>
</div>
</div>
Controller
def report_params
#byebug
params.require(:report).permit(:subject, :description, hero_ids: [])
end
Console
(byebug) params.require(:report)
<ActionController::Parameters {"subject"=>"Test report", "description"=>"Test report", "hero_ids"=>"1"} permitted: false>
I have a nested form which is currently working, except that everytime I would add a nested form, it will display the calendar for each field on a click. Meaning, if there are 5 nested form each with a Start and End date, once the user clicks on the calendar icon, it will open 10 datetimepicker.
<div class="input-group date datepicker">
<%= f.text_field(:start, value: f.object.start ? f.object.start.strftime('%B %d, %Y') : nil, class: "form-control datetimepicker", data: {target: ".datetimepicker"}, placeholder: "#{t :From}", required: true) %>
<div class="input-group-append" data-target=".datetimepicker" data-toggle="datetimepicker">
<div class="input-group-text"><span class="fas fa-calendar-alt"></span></div>
</div>
</div>
</tr>
<tr>
<div class="input-group date datepicker">
<%= f.text_field(:end, value: f.object.end ? f.object.end.strftime('%B %d, %Y') : nil, class: "form-control datetimepicker", data: {target: ".datetimepicker"}, placeholder: "#{t :End_time_or_until}", required: true) %>
<div class="input-group-append" data-target=".datetimepicker" data-toggle="datetimepicker">
<div class="input-group-text"><span class="fas fa-calendar-alt"></span></div>
</div>
</div>
</tr>
Anybody knows how to integrate this ?
I have this in my main form's JS :
$(document).on('ready page:change', function() {
insertedItem.find('.datepicker').datepicker()
$('#invsessions').on('cocoon:after-insert', function() {
$('.datetimepicker').datetimepicker();
})
})
On this case, I add the nested form twice.