Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined method include? for Nil:NilClass

Thanks for answering my previous question, but I ran into a new problem.

I'm creating a custom validator that validates whether a user typed in a clean word. This is used on my UsersController as a validation method.

I am using the Obscenity gem but created some of my own methods to ensure quality data.

Error Message

NoMethodError: Undefined method include? for Nil:NilClass

The problem with this is that my methods work if a record already exists, but they don't work during record creation. I've tried to combat this problem by using

:on => [:create, :update]

but I still receive the same error.

Validation Methods

class MyValidator < ActiveModel::Validator

  def mystery_setup
    @mystery_words = # This is a mystery, I can't tell you.
    @mystery_c = @mystery_words.map(&:capitalize)
    @mystery_u = @mystery_words.map(&:upcase)
    @mysteries = @mystery_words + @mystery_c + @mystery_u
    @new_mysteries = @mysteries.map{|mystery|mystery.tr("A-Za-z", "N-ZA-Mn-za-m")}
 end

  def validate (user)
  mystery_setup
    if Obscenity.profane?(user.name) \ 
    || @new_mysteries.any?{|mystery|user.name.include?(mystery)} \
    || @new_mysteries.any?{|mystery|user.email.include?(mystery)} \
    || @new_mysteries.any?{|mystery|user.password.include?(mystery)}
      user.errors[:name] << 'Error: Please select a different username'
    end
  end
end

User.rb(Model)

class User < ActiveRecord::Base

  include ActiveModel::Validations
  validates_with MyValidator

  has_many :favorites, foreign_key: "user_id", dependent: :destroy
  has_many :pictures, through: :favorites

  has_secure_password
  before_create :create_remember_token

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

  validates_presence_of :name, :password, :email
  validates_uniqueness_of :name, :email
  validates :name, length: { in: 3..20 }
  validates :password, length: { minimum: 6 }
  validates :email, format: { with: VALID_EMAIL_REGEX }, length: { in: 8..50 }

  validates_confirmation_of :password, if: lambda { |m| m.password.present? }

  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end

  def User.digest(token)
    Digest::SHA1.hexdigest(token.to_s)
  end

  private

  def create_remember_token
    self.remember_token = User.digest(User.new_remember_token)
  end

end

I have also tried using an unless statement

def validate (user)
  mystery_setup
  unless User.all.include?(user)
    if (Obscenity.profane?(user.name) 
    || @new_mysteries.any {|mystery|user.name.include?(mystery)})  \
    || @new_mysteries.any?{|mystery|user.email.include?(mystery)} \
    ||   @new_mysteries.any?{|mystery|user.password.include?(mystery)}
        user.errors[:name] << 'Error: Please select a different username'
      end
    end
  end
end

I tried testing if there was a user by using the unless statement but that didn't work either.

Following advice from a similar question here, I changed my migrations file to combat this area.

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name, default: 'new'
      t.string :password, default: 'new'
      t.string :email, default: 'new'

      t.timestamps
    end
  end
end

Question Link

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

Reference for Code

http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations

Changing the migration file by changing the default values didn't solve this question so I decided to ask a new question here.

This method works for updating records but not for creating new records.

Help is appreciated. Thank you in advanced.

Edit

Just received an excellent suggestion to pass in the attributes in bracket format. My code now looks like this

def validate (user)
    mystery_setup
    unless User.all.include?(user)
      if (Obscenity.profane?(user[:name]) || 
        @new_mysteries.any?{|mystery|user[:name].include?(mystery)})  \
      ||@new_mysteries.any?{|mystery|user[:email].include?(mystery)}
      ||@new_mysteries.any?{|mystery|user[:password].include?(mystery)}
        user.errors[:name] << 'Error: Please select a different username'
      end
    end
end

Right now, it only has an error with the email and password attributes. If I delete the last two ||@new_mysteries.any? lines, my method works for filtering the name.

I would like to keep this professional though, so I'd like to get it to work with the other two methods. Possibly has to do with my use of parentheses or the || symbol?

Solid progress guys, keep it up.

Edit

Also, if I would like to call these validation methods on other classes, would it be better to put this in a helper file?

New Update

Here is my Users Controller code

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update]

  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Congratulations #{@user.name}! You have successfully created an account"
      redirect_to games_path
    else
      render 'new'
    end
  end

  def edit
  end

  def update
    @user = User.find(params[:id])
  end

  def favorites
    @user = User.find(current_user)
  end

  def destroy
  end

  private

    def user_params
     params.require(:user).permit(:name, :email, :password, :password_confirmation)
   end

   def signed_in_user
     unless signed_in?
       store_location
       redirect_to signin_url notice: "Please sign in."
     end
   end

   def correct_user
     @user = User.find(params[:id])
     redirect_to(root_url) unless current_user?(@user)
   end
end
like image 301
Darkmouse Avatar asked Dec 05 '22 05:12

Darkmouse


1 Answers

You could write that like this:

def validate (user)
  mystery_setup
  user.errors[:name] << 'Tsk! Tsk! Please select a different username' if
    Obscenity.profane?(user[:name]) ||
      [:name, :email, :password].product(@new_mysteries).any? { |sym, mystery|
        (str = user.public_send sym) && str.include?(mystery) }
end

Thanks to @Arup for the fix.

If you wished to reduce the number of instance variables, you could change the first line to:

new_mysteries = mystery_setup

and change @new_mysteries to new_mysteries.

like image 161
Cary Swoveland Avatar answered Dec 26 '22 13:12

Cary Swoveland