0

I'm trying to combine two form inputs into one database entry parameter. In my form I have dropdown for hours (6-22) and for mins (0-55) and in my db I have a column 'start' where I would like to have an integer calculated as start_hour * 60 + start_mins.

My form looks like that:

<div class="form-group">
  <%= f.label :start_hour %>
  <%= f.select :start_hour, 6 .. 22, class: 'form-control' %>

  <%= f.label :start_mins %>
  <%= f.select :start_mins, 00 .. 55, class: 'form-control' %>
</div>

In my model I added before_validation:

before_validation :generate_starttime

 def generate_starttime
      self.start= '#{:start_hour}' * 60 + '#{start_mins}'
 end

and I have a problem with my controller - I don't know how to pass start into the db. I'm passing params as:

def create
    @klass = Klass.new(contact_params)
    if @klass.save
        flash[:success] = "Class added"
    else
        flash[:error] = @klass.errors.full_messages.join(", ")
    end
    redirect_to new_klass_path
end

and I tried self.start and @start and :start and nothing really works - but I admit I stay in the dark. For now I receive and error:

undefined method `start' for # Did you mean? status

for "self.start" version and

undefined method `start_mins' for # Did you mean? start start_was

for ":start" and "@start" version :D I feel like I'm missing some very basics here. Could you point me into the right direction?

If that is important that's my db schema:

create_table "klasses", force: :cascade do |t|
  t.string  "name"
  t.string  "teacher"
  t.string  "day"
  t.integer "start"
  t.integer "duration"
end
Malvinka
  • 1,185
  • 1
  • 15
  • 36
  • 2
    Have you checked this [Using multiple input fields for one attribute](https://stackoverflow.com/questions/11144030/using-multiple-input-fields-for-one-attribute) – Vane Trajkov Dec 21 '17 at 20:45
  • @VaneTrajkov thank you. I missed that one tbh. I am trying to use that one, I get rid of the error but still my :start attr in the db is set to 0. – Malvinka Dec 21 '17 at 21:10

2 Answers2

2

Try adding attr_accessor :start_hours, :start_mins to your model. In addition, whitelist these two fields in your contact_params. You can find more information on attr_accessor over here.

Stephan Rodemeier
  • 717
  • 10
  • 24
  • 1
    Thanks! That helps to get rid of the error I got. But still I have problem with passing :start value into db. Now the entry is added but that value is set to 0. – Malvinka Dec 21 '17 at 21:08
  • I would change the model so you are actually saving `start_hours` and `start_mins` to the database. `start` can then simply be a method on the model that calculates the time when you need it. This way, you can also edit the model using the same form, since the fields are still separate. – Stephan Rodemeier Dec 21 '17 at 21:24
  • But I do not need these two separate vals in any moment, these are only to make the form more readable (I could use a text_field and require HH:MM form as well just decided it will be more idiot-proof) - I use everywhere an integer form. Can't see the point in adding additional col into db... – Malvinka Dec 21 '17 at 21:27
  • If you really have no need for the user to edit a `Klass`, then you don't need to save them separately. Try to change your method to something like `self.start= start_hour.to_i * 60 + start_mins.to_i`. – Stephan Rodemeier Dec 21 '17 at 21:37
  • 1
    Be aware that by using a callback, you will get an error if ever the record is loaded and re-validated without `start_hour` and `start_mins` attributes present. I would change to `self.start = start_hour.to_i * 60 + start_mins.to_i if start_hour && start_mins`. – moveson Dec 21 '17 at 21:43
  • Right. So I added attr_accessor and whitelisted these fields as you suggested. And in 'create' method I added a line: @klass.start = '#{:start_hour}' * 60 + '#{start_mins}'. but the value actually saved in my db is 0. As if start_hour and start_mins were not read properly or as it was not calculated at all? – Malvinka Dec 21 '17 at 21:53
  • Try adding the code that moveson suggested to your `Klass#generate_starttime`. That should do the trick ^^ – Stephan Rodemeier Dec 21 '17 at 22:13
2

Here is one possible solution. Note that the code samples below are assuming that the model name is Klass and named everything according to it. Feel free to update the naming to serve your application names

Your view would look something like:

<%= form_with(model: klass, local: true) do |f| %>
...
<div class="form-group">
  <%= f.label :start_hour %>
  <%= f.select :start_hour, 6 .. 22, class: 'form-control' %>

  <%= f.label :start_mins %>
  <%= f.select :start_mins, 00 .. 55, class: 'form-control' %>
</div>
...
<% end %>

In your Controller, you define a before_action that will calculate the start param

class KlassesController < ApplicationController
  before_action :fix_params, only: [:create, :update]
...

  private

    def klass_params
      params.require(:klass).permit(:name, :teacher, :day, :start, :duration)
    end

    def fix_params
      if params[:klass].blank?
        # parent not provided
        return
      end
      start_hour = params[:klass].delete(:start_hour)
      start_mins = params[:klass].delete(:start_mins)

      if start_hour.blank? || start_mins.blank?
        # consider handling this case
      else
        params[:klass][:start] = start_hour.to_i * 60 + start_mins.to_i
      end
    end

...
end

and your create handler

def create
    @klass = Klass.new(klass_params)
    if @klass.save
        flash[:success] = "Class added"
    else
        flash[:error] = @klass.errors.full_messages.join(", ")
    end
    redirect_to new_klass_path
end

Hope this helps!

Vane Trajkov
  • 758
  • 4
  • 11
  • Thank you! It works! The only thing is: I've got an error when using your solution in the first line: "undefined local variable or method `klass' " (yes, my model is named Klass). I use <%= form_for @klass do | f | %> and it works that way, what's the difference? – Malvinka Dec 21 '17 at 22:32
  • Not sure where the problem would be, to be honest. From Rails 5.1 [`form_with` is just a unification of form_for and form_tag](http://edgeguides.rubyonrails.org/5_1_release_notes.html#unification-of-form-for-and-form-tag-into-form-with). Have you tried just providing the `@` sign in my sample `<%= form_with(model: @klass, local: true) do |f| %>` – Vane Trajkov Dec 21 '17 at 22:44
  • Yes, I tried and get some other problem (sorry, can't check now which one exactly, I'll check that tomorrow). Thank u for your help! – Malvinka Dec 21 '17 at 22:54