Will Sheehan Will Sheehan - 11 months ago 45
Ruby Question

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

In my view

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

<% @units.each do |unit| %>
<td><%= unit.course %></td>
<td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
<% 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


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

  def set_default_mailing_date
    self.mailing_date ||= Date.today

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>