I'm trying to add time_select with include_blank. I'm doing this:
    <%= f.time_select :start_at, include_blank: true, ampm: true %><br>
What I'd like to do is to delete value (save nil?) if blank is selected in view.
Although I tried the following posts, it didn't work for me.
time_select blank field saves a default time when form is submitted
Optional time_select with allow_blank defaults to 00:00
1) When I try as below, no error is appeared, but 00:00:00 is saved.
controller
  def update
    @event = Event.find(params[:id])
    if event_params["start_at(4i)"].blank? or event_params["start_at(5i)"].blank?
      @event.start_at = nil
    end
    if @event.update(event_params)
      flash[:success] = "event updated!"
      redirect_to root_url
    else
      render 'edit'
    end
  end
2) When I try as below (change if clause), no error is appeared, but 00:00:00 is saved.
controller
  def update
    @event = Event.find(params[:id])
    if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
      @event.start_at = nil
    end
    if @event.update(event_params)
      flash[:success] = "event updated!"
      redirect_to root_url
    else
      render 'edit'
    end
  end
3) When I try as below (add before_action), no error is appeared, but 00:00:00 is saved.
controller
  before_action :blank_time,     only: [:update]
  def update
    @event = Event.find(params[:id])
    if @event.update(event_params)
      flash[:success] = "event updated!"
      redirect_to root_url
    else
      render 'edit'
    end
  end
  private
    def blank_time
      if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
        params[:id]['start_at(1i)'] = ""
        params[:id]["start_at(2i)"] = ""
        params[:id]["start_at(3i)"] = ""
        params[:id]["start_at(4i)"] = ""
        params[:id]["start_at(5i)"] = ""
      end
    end
4) When I try as below (use nil instead of ""), error is appeared.
error
IndexError (string not matched):
  app/controllers/events_controller.rb:106:in `[]='
  app/controllers/events_controller.rb:106:in `blank_time'
controller
  before_action :blank_time,     only: [:update]
  def update
    @event = Event.find(params[:id])
    if @event.update(event_params)
      flash[:success] = "event updated!"
      redirect_to root_url
    else
      render 'edit'
    end
  end
  private
    def blank_time
      if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
        params[:id]['start_at(1i)'] = nil
        params[:id]["start_at(2i)"] = nil
        params[:id]["start_at(3i)"] = nil
        params[:id]["start_at(4i)"] = nil
        params[:id]["start_at(5i)"] = nil
      end
    end
It would be appreciated if you could give me any advice.
UPDATE
Although I change the edit in events_controller.rb as below, the error ActiveModel::MissingAttributeError (can't write unknown attribute 'start_at(4i)'): is displayed.
  def edit
    @room = Room.find(params[:room_id])
    @event = @room.events.find(params[:id])
    @event['start_at(4i)'] = @event.start_at.split(':')[0]   #the error occur here
    @event['start_at(5i)'] = @event.start_at.split(':')[1]
  end
                My idea works like this:
Migration:
class CreateTests < ActiveRecord::Migration[5.0]
def change
create_table :tests do |t|
  t.string :time
  t.timestamps
end
end
end
Form:
<%= form_for(test) do |f| %>
<% if test.errors.any? %>
<div id="error_explanation">
  <h2><%= pluralize(test.errors.count, "error") %> prohibited this test from being saved:</h2>
  <ul>
  <% test.errors.full_messages.each do |message| %>
    <li><%= message %></li>
  <% end %>
  </ul>
</div>
<% end %>
<div class="field">
<%= f.label :time %>
<%= f.time_select :time, include_blank: true, ampm: false %><br>
</div>
<div class="actions">
 <%= f.submit %>
 </div>
<% end %>
Controller: This will save : when value send are null where you can use conditional to check if parameters are null or and set value of time. //It's consuming much time and I skipped for you to complete.
def create
@test = Test.new(test_params)
@time = (params[:test]['time(4i)']).to_s
@time_ampm = (params[:test]['time(5i)']).to_s
@test.time = @time+":"+ @time_ampm
respond_to do |format|
  if @test.save
    format.html { redirect_to @test, notice: 'Test was successfully created.' }
    format.json { render :show, status: :created, location: @test }
  else
    format.html { render :new }
    format.json { render json: @test.errors, status: :unprocessable_entity }
  end
end
end
For updating
def edit
 @test = Test.find(params[:id])
 @test['time(4i)'] = @test.time.split(':')[0]
 @test['time(5i)'] = @test.time.split(':')[1]
end
def update
  @test = Test.find(params[:id])
  @time = (params[:test]['time(4i)']).to_s
  @time_ampm = (params[:test]['time(5i)']).to_s
  @test.time = @time+":"+ @time_ampm
  @test.update(test_params)
end
                        Assigning @event.starts_at to nil does nothing as the attributes in #event_params is used when calling #update,  overwriting your initial assignment. 
Overwriting the starts_at attribute in your params should work instead.
def update
    @event = Event.find(params[:id])
    if event_params["start_at(4i)"].blank? or event_params["start_at(5i)"].blank?
      event_params = event_params.reject { |k, v| k.starts_with? 'starts_at' }
                                 .merge(starts_at: nil)
    end
    if @event.update(event_params)
      flash[:success] = "event updated!"
      redirect_to root_url
    else
      render 'edit'
    end
end
The following line finds and remove the parameters for starts_at(1i) to starts_at(5i), then sets the whole starts_at attribute  to be nil:
event_params.reject { |k, v| k.starts_with? 'starts_at' }.merge(starts_at: nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With