I'm trying to extend ActiveRecord with the custom validation method validate_as_email so i could use it like this:
class User < ActiveRecord::Base
validates_as_email :email
end
I found description on how to extend ActiveRecord::Base class here: http://guides.rubyonrails.org/activerecord_validations_callbacks.html
It says you have to create a *.rb class under config/initializers/{myfile}.rb.
ActiveRecord::Base.class_eval do
def self.validates_as_email(attr_name)
validate is_email_fn(attr_name)
end
end
What do I have to do next so I could use validates_as_email in my model and where should I put is_email_fn() function.
hope this will help you http://marklunds.com/articles/one/312
Related
We have a multi-tenant application where validation differs for each account. We could easily achieve this for presence validation like the below,
module CommonValidator
def add_custom_validation
required_fields = get_required_fields
return if required_fields.blank?
validates_presence_of required_fields.map(&:to_sym)
end
end
class ApplicationRecord < ActiveRecord::Base
include Discard::Model
include CommonValidator
end
Then we have to add uniqueness validation based on account, so tried like the same. but getting undefined method error. Is there any way that I could get this work?
module CommonValidator
def add_custom_validation
unique_fields = ['first_name']
validates_uniqueness_of unique_fields.map(&:to_sym) if unique_fields.present?
end
end
validates_uniqueness_of is actually a class method (defined in ActiveRecord::Validations::ClassMethods), hence you are not able to call it from the context of the object.
Whereas validates_presence_of is both a helper method, and a class method (defined in ActiveModel::Validations::HelperMethods and ActiveRecord::Validations::ClassMethods).
If you want to use the uniqueness validator, you can define the add_custom_validation as a class method as well and then you should be able to use it. Something like,
require 'active_support/concern'
module CommonValidator
extend ActiveSupport::Concern
included do
add_custom_validation
end
class_methods do
def add_custom_validation
required_fields = get_required_fields # This will also need to be a class method now
return if required_fields.blank?
validates_uniqueness_of required_fields.map(&:to_sym)
end
end
end
I'm building an API with Rails 4.1. One of my calls takes 2 input fields and makes a call to a third party API to get more data. It then uses that data to make an ActiveRecord model.
How should I validate the input? I'm not making a model from the 2 input fields.
Note: They need to be validated before making the call to the third party API
From what you've written, I would say you want to look at attr_accessor and use ActiveRecord to validate your form data:
#app/models/model.rb
Class Model < ActiveRecord::Base
attr_accessor :your, :inputs
validates :your, :inputs, presence: true
end
This will create virtual attributes which you can then validate using the standard ActiveRecord validation functionality. I believe that, as your model will typically create instance methods for your datatable's attributes, you'll be able to achieve the same functionality with attr_accessor attributes
As mentioned by #Mohammed, you'll then be able to validate the inputs by creating an instance of the model with your data:
#app/controllers/your_controller.rb
Class Controller < ApplicationController
def create
#model = Model.new(input_params)
#model.valid?
end
private
def input_params
params.require(:model).permit(:your, :inputs)
end
end
Perhaps a form object would work for you: http://robots.thoughtbot.com/activemodel-form-objects
Are will these inputs be used as attibutes in the model? If so, why not initialise a new object and test for validity?
def new
foo = Foo.new(inputs)
foo.valid?
end
Otherwise you can use a plain old PORO that extends ActiveModel::Model module to imitate an AR model (validations and so forth). You can find more detail on this here: http://blog.remarkablelabs.com/2012/12/activemodel-model-rails-4-countdown-to-2013
Is it possible to setup a system wide validation callback?
I want to write a logger for every validation failure that occur in any model. This callback should not change the behaviour of any other callback that is setted in the models.
I need it to provide faster support to my customers, my idea is to log all validation errors so the support team is able to find out what is going on faster.
Although #MurifoX's answer might work with some configuration I prefer to avoid inheritance from ActiveRecord::Base when possible. Since SuperModel inherits from ActiveRecord::Base it may look like its an actual model which has a representation in the Database side, whereas it only exists to be inherited from.
In my opinion, a better solution to your problem would be Ruby Mixins:
# lib/validation_logger.rb
module ValidationLogger
def self.included(base)
base.class_eval do
after_validation :log_validation
end
end
def log_validation
#custom log here
end
end
Now you should just include ValidationLogger in models you would like to log.
Maybe make all your models inherit from one common super-model that inherits from ActiveRecord::Base.
def FirstModel < SuperModel
end
def SecondModel < SuperModel
end
def ThirdModel < SuperModel
end
And then, you put your callback on the super-model:
def SuperModel < ActiveRecord::Base
after_validation :do_your_thing
def do_your_thing
# stuff
end
end
I have a model which includes a module. I'd like to override the model's accessor methods within the module.
For example:
class Blah < ActiveRecord::Base
include GnarlyFeatures
# database field: name
end
module GnarlyFeatures
def name=(value)
write_attribute :name, "Your New Name"
end
end
This obviously doesn't work. Any ideas for accomplishing this?
Your code looks correct. We are using this exact pattern without any trouble.
If I remember right, Rails uses #method_missing for attribute setters, so your module will take precedence, blocking ActiveRecord's setter.
If you are using ActiveSupport::Concern (see this blog post, then your instance methods need to go into a special module:
class Blah < ActiveRecord::Base
include GnarlyFeatures
# database field: name
end
module GnarlyFeatures
extend ActiveSupport::Concern
included do
def name=(value)
write_attribute :name, value
end
end
end
I have a model named Calendar.
The validations that will be applied to it varies from the selections made by the user.
I know that I can use custom validation + conditional validation to do this, but doesn't look very clean to me.
I wonder if I can store it on a database column and pass it to a "generic" validator method.
What do you think?
Explaining further:
A user has a calendar.
Other users that have access to this calendar, can schedule appointments.
To schedule an appointment the app should validate according to the rules defined by the calendar's owner.
There are many combinations, so what I came to is:
Create custom validator classes to each of the possible validations and make then conditional.
class Calendar
validate_allowed_in_hollydays :appointment_date if :allowedinhollydays?
(tenths of other cases)
...
end
This works, but feels wrong.
I'm thinking about storing somewhere which rules should be applied to that calendar and then doing something like:
validate_stored_rules :appointment_date
It seems a little backwards to save the data in the database and then validate it.
I think your initial thought of going with some custom validation is the best bet. validates_with looks like your best option. You could then create a separate class and build all the validation inside that to keep it separate from your main model.
class Person < ActiveRecord::Base
validates_with GoodnessValidator
end
class GoodnessValidator < ActiveModel::Validator
def validate
if record.first_name == "Evil"
record.errors[:base] << "This person is evil"
end
end
end
Code lifted straight from the Rails Validation Guide
you should use with_options it allows to put default options into your code:
class User < ActiveRecord::Base
with_options :if => :is_admin do |admin|
admin.validates_length_of :password, :minimum => 10
end
end
in the example is_admin might be an database column, attr_accessor or an method
Thank you all for your help.
I've got it working like this:
def after_initialize
singleton = class << self; self; end
validations = eval(calendar.cofig)
validations.each do |val|
singleton.class_eval(val)
end
end