Question

I'm building a custom validation method for use in my rails app. The type of validator I want to build compares a column in the model where the validator is called to columns in other tables. The following is a code example that illustrates the pattern of the validator I am trying to build.

module ActiveModel
    module Validations
        module ClassMethods
            # example: validate_a_column_with_regard_to_other_tables :column, tables: { table_one: :some_column }
            def validate_a_column_with_regard_to_other_tables(*attr_names)
                validates_with WithRegardToOtherTablesValidator, _merge_attributes(attr_names)
            end
        end

        class WithRegardToOtherTablesValidator < EachValidator
            def validate_each(record, attribute, value)
                # compare record, attribute or value to all records that match table: :column in :tables
            end
        end
    end
end

It is possible to test this using the models that exist in the app and schema. However, this is not a good way to test the validator because it would describe the validator as being dependent on models that it is not dependent on.

The only other way I can think of is to create a set of mock up models in the test.

class ValidateModel < BaseModel
    validate_a_column_with_regard_to_other_tables :column, :tables { compare_to_model: :some_column }
end

class CompareToModel < BaseModel
    attr_accessor :some_column
end

However, it is not possible to validate that :column has something to do with :some_column in :compare_to_model because :compare_to_model is not part of the schema.

How do you create a mock model that is part of your schema in tests? Or is there a better way to test a custom validator function like this?

Was it helpful?

Solution

If you're using rspec you could set up something like this:

before(:all) do
  ActiveRecord::Migration.create_table :compare_to_model do |t|
    t.string :some_column
    t.timestamps
  end
end

it "validates like it should" do
  ...
end

after(:all) do
  ActiveRecord::Migration.drop_table :compare_to_model
end
  • One note on before(:all) it is a "global" setup so the data would persist from one it to the other, you might want to wrap each it with a transaction and roll it back after or instead have a before(:each) that will clean the table.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top