undefined method `include?' for nil:NilClass with partial validation of wizard gem
Asked Answered
H

3

14

I am trying to follow the guide for partial validation on object using the wizard gem, but I keep getting the error undefined method `include?' for nil:NilClass, cant understand what is wrong, have tried to follow the step by step instructions.

The error in the log shows.

NoMethodError - undefined method `include?' for nil:NilClass:
app/models/property.rb:22:in `active_or_tenants?'

Here is my steps controller.

class Properties::BuildController < ApplicationController
  include Wicked::Wizard

  steps :tenant, :confirmed 

  def show
    @property = Property.find(params[:property_id])
    @tenants = @property.tenants.new(params[:tenant_id])
    render_wizard
  end

  def update
    @property = Property.find(params[:property_id])
    params[:property][:status] = step.to_s
    params[:property][:status] = 'active' if step == steps.last
    @property.update_attributes(params[:property])
    render_wizard @property
  end

  def create
    @property = current_user.properties.build(params[:property])
      logger.info @property.attributes
    if @property.save
        flash[:success] = "Tenant Added"
        redirect_to wizard_path(steps.second, :property_id => @property.id)
    else
        render 'edit'
    end
  end
end

Property.rb

class Property < ActiveRecord::Base
  attr_accessible  :name, :address_attributes, :tenants_attributes, :property_id, :status
  belongs_to :user 

  has_one :address, :as => :addressable
  accepts_nested_attributes_for :address, :allow_destroy => true

  has_many :tenants 
  accepts_nested_attributes_for :tenants, :allow_destroy => true

  validates :name,        :presence => true
  validates :address,     :presence => true
  validates :tenants,     :presence => true, :if => :active_or_tenants?

  def active?
    status == 'active'
  end

  def active_or_tenants?
    status.include?('tenants') || active?
  end
end

Let me know if you need any other parts added to the question. Thanks in advance.

Hamel answered 5/8, 2013 at 16:42 Comment(5)
From which line comes from the error?Gaitskell
line 22 in property.rb NoMethodError - undefined method include?' for nil:NilClass: app/models/property.rb:22:in active_or_tenants?'Hamel
Oh! I see... Status is actually a column (attribute) of the Property class, right? If yes, then replace status.include?('tenants') || active? with (status || '').include?('tenants') || active?Gaitskell
Thats fixed it, could you explain the difference between the two please?Hamel
Yes, I'm gonna post an answer ;)Gaitskell
G
9

From my comments:

The status is an attribute of your Property model. It can be nil which raises an error in certain cases:

undefined method include?' for nil:NilClass

It is actually trying to compare nil to 'tenants' (String).

To fix that, you can use an empty string to be compared if status is nil,

# an example (you can try in your IRB console):
nil || "No value"
# => returns "No value"

in your case:

def active_or_tenants?
  status.to_s.include?('tenants') || active?
end

nil.to_s return an empty string. Which solves your problem ;)


Actually, the methods to_s, to_i, to_f etc. are often used to remove the possible nil:

# in ruby console:
2.3.3 :018 > nil.to_i
# => 0 
2.3.3 :019 > nil.to_f
# => 0.0 
2.3.3 :020 > nil.to_s
# => "" 
2.3.3 :021 > nil.to_a
# => [] 
Gaitskell answered 5/8, 2013 at 17:6 Comment(2)
I am following this guide goo.gl/mKDxey to partial validation of objects using the wizard gem, do you think this would still make the partial validation work?Hamel
Yes because it will return the same thing, The tutorial is not handling the possible nil value for the column "status"Gaitskell
E
2

In Ruby 2.3 you can use the safe navigation operator, which will simply return nil when your object is nil and it won't throw an error.

def active_or_tenants?
  status&.include?('tenants') || active?
end
Electrotonus answered 16/1, 2017 at 7:12 Comment(2)
the attribute status is not an array but a string.Gaitskell
Thanks MrYoshiji, I don't know how I missed that, I'll update my answer.Electrotonus
A
1

There is another solution to this, you might want to set a default state upon object creation, preferable in the migration.

class AddStatusToProperties < ActiveRecord::Migration
  def change
    create_table :projects do |t|
      t.string :status, default: 'new'
    end
  end
end

Following this you'll never have nil for your state

Areola answered 19/10, 2013 at 16:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.