Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting a 'method-missing' for User call #755

Closed
denaliai-dev opened this issue Mar 14, 2019 · 6 comments
Closed

Getting a 'method-missing' for User call #755

denaliai-dev opened this issue Mar 14, 2019 · 6 comments

Comments

@denaliai-dev
Copy link

denaliai-dev commented Mar 14, 2019

Rails 5.2.2
Ruby 2.6
cient_side_vlidations gem version 13.1.0

I did:

rails g client_side_validations:install

I uncommented the following, in config/initializers/client_side_validations.rb:

ActionView::Base.field_error_proc = proc do |html_tag, instance|
  if html_tag =~ /^<label/
    %(<div class="field_with_errors">#{html_tag}</div>).html_safe
  else
    %(<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>).html_safe
  end
end

Here's what my app/assets/javascript/application.js looks like:

//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require rails.validations
//= require_tree .

I created a folder: app/validators, and added the following two files:

email_validator.rb:

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attr_name, value)
    unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      record.errors.add(attr_name, :email, options.merge(value: value))
    end
  end
end

# This allows us to assign the validator in the model
module ActiveModel::Validations::HelperMethods
  def validates_email(*attr_names)
    validates_with EmailValidator, _merge_attributes(attr_names)
  end
end

and password_validator.rb:

class PasswordValidator < ActiveModel::EachValidator
  def validate_each(record, attr_name, value)
    unless value =~ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/i
      record.errors.add(attr_name, :password, options.merge(value: value))
    end
  end
end

# This allows us to assign the validator in the model
module ActiveModel::Validations::HelperMethods
  def validates_password(*attr_names)
    validates_with PasswordValidator, _merge_attributes(attr_names)
  end
end

In my app/models/user.rb, I have:

class User < ApplicationRecord
  include Shared

  before_create :generate_model_id_and_slug
  validates_email :email # cient side validation of email
  validates_password :password #client side validation of password

  devise :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :lockable, :timeoutable, :trackable and :omniauthable

  validates :email, presence: true
  validates :phone, presence: true
  validates :password, presence: true
end

I also have the following file in app/assets/javascripts: rails.validations.customValidators.js:

// The validator variable is a JSON Object
// The selector variable is a jQuery Object
window.ClientSideValidations.validators.local['email'] = function(element, options) {
  // Your validator code goes in here
  if (!/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i.test(element.val())) {
    // When the value fails to pass validation you need to return the error message.
    // It can be derived from validator.message
    return options.message;
  }
}

// The validator variable is a JSON Object
// The selector variable is a jQuery Object
window.ClientSideValidations.validators.local['password'] = function(element, options) {
  // Your validator code goes in here
  if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/i.test(element.val())) {
    // When the value fails to pass validation you need to return the error message.
    // It can be derived from validator.message
    return options.message;
  }
}

I am not finished with the application yet, but wanted to generate a migration, as follows:

rails g migration add_last_seen_at_to_users last_seen_at:datetime

But, I am getting the following error message:

/Users/joseph/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/activerecord-5.2.2/lib/active_record/dynamic_matchers.rb:22:in `method_missing': undefined method `validates_email' for User (call 'User.connection' to establish a connection):Class
Did you mean?  validates_each (NoMethodError)`
@tagliala
Copy link
Contributor

Hi,

I'm going to check the readme about custom validators, but I do not think this issue is related to CSV.

Could you please remove client side validations and try again?

Also, Devise already provides an e-mail validator and its format is checked on the client side automatically, you don't need a custom one.

If you need to change the format regexp (I advise to use their one, not the one on CSV documentation), you can find it in the devise initializer: https://github.com/plataformatec/devise/blob/master/lib/generators/templates/devise.rb#L174

@denaliai-dev
Copy link
Author

I am familiar with the devise email validator, but that's not what I'm after here. I wanted to do client side validations in general. The email validator is the first thing I'm testing.

I did remove all traces of CSV and ran my migration without any problems. It looks like Rails does not recognize the validators folder. I thought the CSV gem handles that part? I included all the code in my report.

@tagliala
Copy link
Contributor

@denaliai-dev could you please try to run spring stop and retry?

@denaliai-dev
Copy link
Author

The application is not running yet, so I can't run spring stop

@tagliala
Copy link
Contributor

Replicated without CSV.

Repo: https://github.com/tagliala/csv-issue-755

Step-by-step guide:

  1. Clone the repo
  2. Run rails g migration add_last_seen_at_to_users last_seen_at:datetime

I think there are issues with the back-end custom validators.

I'm not going to close here because I think the documentation is wrong or outdated, but I'm going to exclude an issue with CSV itself

Feel free to comment and let me know what is causing the issue, it may be helpful to others.

I've noticed that my custom validators (example: https://github.com/DavyJonesLocker/client_side_validations/wiki/Custom-Validators#remote-validators) do not include the ActiveModel::Validations::HelperMethods part and I use it as validates :field, my_custom_validator: true. Neither the examples at rubyonrails.org https://edgeguides.rubyonrails.org/active_record_validations.html#custom-validators

Are we sure that those helpers are still loaded like that in the recent versions of Rails? 🤔

tagliala added a commit to tagliala/csv-issue-755 that referenced this issue Apr 8, 2019
@tagliala
Copy link
Contributor

tagliala commented Apr 8, 2019

@denaliai-dev

Ok, sorry for the very late reply

If you need named validator helpers such as validates_password or validates_email, please move custom validators to config/initializers. This was already covered in the wiki, but I didn't recall why.

I've clarified the wiki and fixed the readme, which was wrongly suggesting to put those named validators in app/validators

Closing here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants