Undefined method includes? for Nil: NilClass

Thanks for answering my previous question, but I am facing a new problem.

I am creating a custom validator that checks if the user enters a blank word. This one is used on my UserController as a validation method.

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

Error message

NoMethodError: Undefined method include? for Nil:NilClass

      

The problem is that my methods work if the record already exists, but they don't work during the creation of the record. I tried to fight this problem using

:on => [:create, :update]

      

but I still get the same error.

Verification 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 the if 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 with an if statement, but that didn't work either.

Following advice from a similar question, I modified the migration 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 master gem check

Link for code

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

Changing the migration file by changing the defaults did not resolve the issue, so I decided to post a new question here.

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

Help is appreciated. Thank you for your promotion.

Edit

Just got a great suggestion to pass attributes in parenthesis format. Now my code looks like

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

      

It currently only has a bug with email and password attributes. If I delete the last two files: \ @ new_mysteries.any? lines, my method works to filter the name.

I would like to keep this professional, so I would like to make it work with two other methods. Perhaps it has something to do with my use of parentheses or || symbol?

Successful guys, keep going.

Edit

Also, if I wanted to name these validation methods for other classes, would it be better to put that in a helper file?

New update

Here is my user 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

      

+3


source to share


7 replies


You can write 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 want to reduce the number of instance variables, you can change the first line to:

new_mysteries = mystery_setup

      

and change @new_mysteries

to new_mysteries

.

+4


source


|| @new_mysteries.any?{|mystery|user.name.include?(mystery)} \
|| @new_mysteries.any?{|mystery|user.email.include?(mystery)} \
|| @new_mysteries.any?{|mystery|user.password.include?(mystery)}

      

This error means that the username, email address, or password is zero. To handle this, you need to change each line like this:

user.name && user.name.include?(mystery)

      



However, we highly recommend a andand

gem that allows you to write the above:

user.name.andand.include?(mystery)

      

+4


source


try it:

def validate (user)
  mystery_setup
  unless User.all.include?(user)
    if user.name && user.email && user.password
      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
end

      

+2


source


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
    mysteries.map{ |mystery| mystery.tr("A-Za-z", "N-ZA-Mn-za-m")}
 end

  def validate (user)
    # No need to pollute the class with instance variables, just pass it back in a return
    new_mysteries = mystery_setup

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

      

+2


source


I edited the code a bit, let me know if this works:

def validate (user)
  mystery_setup

  if Obscenity.profane?(user.name)
    user.errors[:name] << 'Error: Please select a different username'
  end

  %w(name email password).each do |attr|
    value = user.send(attr)
    if value.present? and @new_mysteries.grep(/#{value}/).present?
      user.errors[attr] << "Error: Please select a different user#{attr}"
    end
  end
end

      

+2


source


You have a mistake in this part, in the first line.

@mystery_words = # This is a mystery, I can't tell you.
@mystery_c = mystery_words.map(&:capitalize)

      

It should be

@mystery_words = [] # This is a mystery, I can't tell you.
@mystery_c = mystery_words.map(&:capitalize)

      

+2


source


Since nil

is is Ruby's representation of atomic nonexistence, it never includes anything. The method include?

can simply be defined on it as:

def nil.include? arg
  false
end

      

0


source







All Articles