3

Hy. I'm new to Ruby on Rails and OOP.

I work on a little Scheduler, and want to DRY my Model Methods.
I red some about usage of Module and Class in Rails, but can't find out what is the best way.
difference-between-a-class-and-a-module
ruby-class-module-mixins

Example:

Supposed i have 2 Models ( Datum and Person ).
Each Model has an Attribute which store's a Date, but with different Attribute Name's.

I wrote the same Method for Date Validation in both Module's.

My Models:

class Datum < ActiveRecord::Base
 attr :start_date

 def validate_date
  # same validation stuff with self.start_at
 end
end


class Person < ActiveRecord::Base
 attr :birth_date

 def validate_date
  # same validation stuff with self.birth_date
 end
end


Here is my attempt with a lib/ModelHelper and Datum Model:

class Datum < ActiveRecord::Base
 include ModelHelper

 attr_accessible :start_at

 # Validations
 before_validation :validate_date, :start_at

end


module ModelHelper

 private

 def validate_date *var
  # validation stuff with birth_date and start_at 
 end
end


Question:
In my case, i think i need to assign a Parameter ( for each Model attribute, :start_at and :bith_date ).
But i can't discover how.

What is the best way to DRY my Models, with Module or Class ?
Why and How?

Community
  • 1
  • 1
stephanfriedrich
  • 563
  • 5
  • 20
  • I highly recommend you check out codereview.stackexchange.com – Anthony Dec 05 '14 at 14:23
  • 1
    Incidentally, I recently published an answer on CodeReview.SE about custom Rails 4 validators: http://codereview.stackexchange.com/questions/71435/reservation-validation/71496#71496 – D-side Dec 05 '14 at 14:25
  • @Anthony My Question is not only for Code Review. Its more about understanding Module and Class in Ruby on Rails, with an given Example. – stephanfriedrich Dec 05 '14 at 15:11
  • @D-side thx for your comment, and your Answer is helpful. But it doesn't explain my Question. **What is the best way to DRY my Models, with Module or Class ?** **Why and ...?** I AM PLEASED FOR MORE ANSWERS. – stephanfriedrich Dec 05 '14 at 15:17
  • @stephanfriedrich in this specific context, `validate_date` could be factored out into a validator class. Then you'll only have declarations of attributes and validation rules. DRY enough. – D-side Dec 05 '14 at 15:26

1 Answers1

0

Just as @D-side said in the comments, your best option is to create a Custom Validator.

Create a app/validators directory and add a file with a name like my_date_validator.rb and content like this:

# EachValidator is a validator which iterates through the attributes given in the
# options hash invoking the validate_each method passing in the record, attribute
# and value.
#
# All Active Model validations are built on top of this validator.
#
class MyDateValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value_is_valid? # <- validate in here.
      record.errors[attribute] << (options[:message] || "is not a valid date")
    end
  end
end

and in your models just add:

class Datum < ActiveRecord::Base
  validates :start_date, my_date: true
end

class Person < ActiveRecord::Base
  validates :birth_date, my_date: true
end

The my_date stands for the first part of MyDateValidator class name.

If you name your validator:

  • FooValidator then you use it in your model validations as foo.
  • FooBarValidator then you use it in your model validations as foo_bar.
  • MyDateValidator then you use it in your model validations as my_date.

Also, depending on what you want to validate you may want to look at this Gem:

https://github.com/johncarney/validates_timeliness

DanielBlanco
  • 69
  • 1
  • 4
  • Adding some references here: the preferred place for app-specific validators is `app/validators`, https://github.com/bbatsov/rails-style-guide/blob/master/README.md#app-validators – D-side Dec 05 '14 at 19:12
  • Thanks for your Response. But why don't you use a Model? – stephanfriedrich Dec 05 '14 at 19:48
  • Or in your Example / Rails Guide. What if i try to use more custom validators ( should i write for each Validator c Class ) – stephanfriedrich Dec 05 '14 at 20:13
  • Also i dont understand, what does my_date: true stand for ? And what If i run my validation how i mentioned ( before_validation :validate_date ) ? – stephanfriedrich Dec 05 '14 at 20:39
  • Thank you @D-side I updated the answer based on your comment. – DanielBlanco Dec 05 '14 at 20:42
  • @stephanfriedrich my_date: true stands for "run MyDateValidator" for this attribute. If the validator class name is FooValidator then you write foo: true, if the name is FooBarValidator you write foo_bar: true – DanielBlanco Dec 05 '14 at 20:45