Search code examples
ruby-on-railsrubysimple-form

Conflicting View Logic


I have a show page where I need to both show the student's units and create a unit for them. However an error is being incurred when trying to do both.

In my controller

def show
  @student = Student.find(params[:id])
  @unit = @student.units.build
  @units = @student.units
end

In my view

<%= simple_form_for @unit, url: student_units_path(@student) %>
  # form...
<% end %>

<% @units.each do |unit| %>
  <tr>
    <td><%= unit.course %></td>
    <td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
  </tr>
<% end %>

The unit.course call works and any call that is only the first child of unit, however when I call a second method on unit I get this error:

undefined method `strftime' for nil:NilClass

despite knowing that the unit exists, hence the first call working


Solution

  • It seems your issue is that unit.mailing_date is nil, for newly-built records.

    One solution would be to define a default value for mailing_date, either at the database level or in your application. For example, you could do something like:

    class Unit < ActiveRecord::Base
      # ....
      after_initialize :set_default_mailing_date
    
      private
      def set_default_mailing_date
        self.mailing_date ||= Date.today
      end
    end
    

    Or alternatively, you could leave the mailing_date as nil and handle this gracefully in the view:

    <td><%= unit.mailing_date.try!(:strftime, '%m/%d/%y') %></td>
    

    If you are using ruby version 2.3+, then I would advise using the built-in safe navigation operator, rather than ActiveSupport's try! method:

    <td><%= unit.mailing_date&.strftime('%m/%d/%y') %></td>
    

    Finally, if you went with the above choice to leave the mailing_date as nil, then perhaps you'd like to display some default value in its place - for example:

    <td><%= unit.mailing_date&.strftime('%m/%d/%y') || 'Not set' %></td>