I copied the code from client_side_validations page. And i had error
undefined method validates_email for #<Class:0x007ff3382428a8>
When i put includes ::Validations in my model this error disappeares but validation doesn't work at all.
app/validators/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
config/locales/en.yml
# config/locales/en.yml
en:
errors:
messages:
email: "Not an email address"
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;
}
}
models/comment.rb
class Comment < ActiveRecord::Base
attr_accessible :content, :email, :ip, :name, :post_id
belongs_to :post
validates_presence_of :content, :email, :post_id, :name
validates_email :email
end
I don't see you including your module. Also, depending on where you put your module, you will sometimes need to "require" it. And also, try:
include <Module name>
instead of
includes <Module name>
hope this will help
Related
I have a simple contact form that accepts the following fields (all should be required): Name, Email, phone, and message.
I also want to validate the email address.
Users should be given a response on whether or not the form submitted successfully, or if there are errors.
if so, display specific errors on the view.
This form is not connected to any database model. I'm not saving submissions. Only mailing.
I have a POST route set to contact_form in my PagesController
In my PagesController I have
def contact_form
UserMailer.contact_form(contact_form_params).deliver
end
In my UserMailer class I have:
def contact_form(params)
#formParams = params;
#date = Time.now
mail(
to: "support#example.com",
subject: 'New Contact Form Submission',
from: #formParams[:email],
reply_to: #formParams[:email],
)
end
This mails successfully, but there's no validation. I need to only run the mail block if validation passes. then return a response to the user.
Since I have no Model, I'm not sure how to do this. All the answers I see tell people to use validates on the ActiveRecord model.
With the few answers:
(note I've updated my params)
class UserMailerForm
include ActiveModel::Validations
def initialize(options)
options.each_pair{|k,v|
self.send(:"#{k}=", v) if respond_to?(:"#{k}=")
}
end
attr_accessor :first_name, :last_name, :email, :phone, :message
validates :first_name, :last_name, :email, :phone, :message, presence: true
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
end
def contact_form
#form = UserMailerForm.new(contact_form_params)
if #form.valid?
UserMailer.contact_form(contact_form_params).deliver
else
logger.debug('invalid')
logger.debug(#form.valid?)
end
end
This sends mail when valid. However, I'm still unsure about sending info to the user
You can make UserMailer a model and use validations on that.
class UserMailer
include ActiveModel::Model # make it a model
include ActiveModel::Validations # add validations
attr_accessor :name, :email, :phone, :message
validates :name, :email, :phone, :message, presence: true
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
def send_mail(subject:, to:)
mail(
to: to,
subject: subject,
from: email,
reply_to: email,
)
end
end
Then use it like any other model.
def UserMailersController < ApplicationController
def new
#user_mailer = UserMailer.new
end
def create
#user_mailer = UserMailer.new(params)
if #user_mailer.valid?
#user_mailer.send_mail(
to: "support#example.com",
subject: 'New Contact Form Submission',
)
else
# Use #user_mailer.errors to inform the user of their mistake.
render 'new'
end
end
end
If you have multiple forms associated with UserMailer, you can make separate classes to validate each Form's inputs and then pass them along to UserMailer. You'd likely still want validations on UserMailer regardless.
You can use ActiveModel::Validations on your PORO the same way AR does this.
class MyFormObject
include ActiveModel::Validations
def initialize(options)
options.each_pair{|k,v|
self.send(:"#{k}=", v) if respond_to?(:"#{k}=")
}
end
attr_accessor :name, :email, :phone, :message
validates :name, presence: true
# and so on...
end
I try to add an email-validator in my rails app. I created the following file /lib/validators/email_validator.rb
class EmailValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
object.errors[attribute] << (options[:message] || "is not formatted properly")
end
end
end
In the application.rb I added this line:
config.autoload_paths << "#{config.root}/lib/validators"
And here is my User model:
class User < ActiveRecord::Base
attr_accessible :email, :password,:name
validates :email, :presence => true, :uniqueness => true, :email => true
end
If i want to start the server I got an error:
Unknown validator: 'EmailValidator' (ArgumentError)
Has anybody an idea how I can fix this problem?
If you place your custom validators in app/validators they will be
automatically loaded without needing to alter your
config/application.rb file.
Resource: Where should Rails 3 custom validators be stored? (second answer)
This error occures, because rails loads model file before your validation file
Try to require your validation file manually at the start of your model file
require_dependency 'validators/email_validator.rb'
Try the modified User model;
class User < ActiveRecord::Base
attr_accessible :email, :password,:name
validates :email, :presence => true, :uniqueness => true
end
My Rails skills is (to be kind) rusty so this is probably a newbie question. I'm trying to create a simple email sending form, but I keep getting:
NoMethodError in Mail#create
undefined method `model_name' for Mail::Message:Class
I'm pretty sure that my problem is in my controller, the relevant method looks like this:
def create
#mail = Mail.new(params[:mail])
MailMailer.send_mail(#mail).deliver
end
Thinks this line is causing the error #mail = Mail.new(params[:mail]). My Mail model class looks like this:
class Mail < ActiveRecord::Base
include ActiveModel::Validations
validates :password, :presence => true
attr_accessor :password, :to, :cc, :bcc, :from, :subject, :message
end
And my mailer looks like this:
class MailMailer < ActionMailer::Base
def send_mail(mail)
mail(:to => mail.to, :subject => mail.subject)
end
end
Can anyone spot what I'm doing wrong?
Your problem is probably right here:
class Mail < ActiveRecord::Base
# ---------^^^^^^^^^^^^^^^^^^
include ActiveModel::Validations
validates :password, :presence => true
attr_accessor :password, :to, :cc, :bcc, :from, :subject, :message
end
Subclassing ActiveRecord::Base and including ActiveModel::Validations is a bit odd as AR already includes all the validation stuff. Mixing AR and attr_accessor is another sign that something strange is going on.
In your comments you note that you created this model with:
$ rails g model mail
And that tries to create a database-backed ActiveRecord model as that's almost always what people want. You might also run into trouble because Mail is already in use so maybe you want to use a different name.
If you just want a model that is just a temporary bag of data then you can do this:
class SomeEmail
attr_accessor :password, :to, :cc, :bcc, :from, :subject, :message
end
You probably don't need the validations here but you can add them:
class SomeEmail
include ActiveModel::Validations
validates :password, :presence => true
attr_accessor :password, :to, :cc, :bcc, :from, :subject, :message
end
but the validations won't be triggered unless you manually call valid? so there's no much point.
Finally, just adding attr_accessor doesn't give you a useful constructor so with all of the above changes, this:
#mail = SomeMail.new(params[:mail])
still won't do what you want as nothing in params[:mail] will get saved anywhere. So add an initialize implementation to your email class and a call to valid? to your controller.
I put EmailValidator in lib/validators/email_validator and it's not workings (I put root/lib in the load_path)
here is the code.. I put the class in module validators as the parent folder name
class Validators::EmailValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#([a-z0-9]+\.)+[a-z]{2,}$/i
object.errors[attribute] << (options[:message] || "is not formatted properly")
end
end
end
I get the error Unknown validator: 'email'
You have two options:
Either put your custom validator under config/initializers.
Or add lib/validators to the autoload path in config/application.rb.
config.autoload_paths << "#{config.root}/lib/validators"
Personally I would go with the second option as lib/validators makes for good encapsulation.
Since you put your custom validator in the Validators:: in the lib/validators, you have to reference it with that namespace also.
validates :email, presence: true, :'validators/email' => true
UPDATE: You need this:
module Validators
class EmailValidator < ActiveModel::EachValidator
def validate(object, attribute, value)
unless value =~ /^([^#\s]+)#([a-z0-9]+\.)+[a-z]{2,}$/i
object.errors[attribute] << (options[:message] || "is not formatted properly")
end
end
end
end
class YourModel < ActiveRecord::Base
include Validators
validates :email, :presence => true, :email => true
end
Otherwise, you need to put your validator class under the ActiveModel::Validations namespace. When you namespace a class, ActiveRecord isn't going to see it, if that namespace isn't a namespace it has already included.
After searching for a tableless model example I came across this code which seems to be the general consensus on how to create one.
class Item < ActiveRecord::Base
class_inheritable_accessor :columns
self.columns = []
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
def all
return []
end
column :recommendable_type, :string
#Other columns, validations and relations etc...
end
However I would also like it to function, as a model does, representing a collection of object, so that I can do Item.all.
The plan is to populate Items with files and each Item's properties will be extracted from the files.
However currently if I do Item.all I get a
Mysql2::Error Table 'test_dev.items' doesn't exist...
error.
I found an example at http://railscasts.com/episodes/219-active-model where I can use model features and then override static methods like all (should have thought of this before).
class Item
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :content
validates_presence_of :name
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
class << self
def all
return []
end
end
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
Or you could do it like this (Edge Rails only):
class Item
include ActiveModel::Model
attr_accessor :name, :email, :content
validates_presence_of :name
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
end
By simply including ActiveModel::Model you get all the other modules included for you. It makes for a cleaner and more explicit representation (as in this is an ActiveModel)