{"id":25527584,"url":"https://github.com/vprokopchuk256/mv-core","last_synced_at":"2025-06-11T02:03:29.265Z","repository":{"id":1406392,"uuid":"1459131","full_name":"vprokopchuk256/mv-core","owner":"vprokopchuk256","description":"Migration Validators project core classes","archived":false,"fork":false,"pushed_at":"2016-12-31T02:43:15.000Z","size":530,"stargazers_count":24,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-11T02:02:58.496Z","etag":null,"topics":["activerecord","constraints","db-constraints","ror"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"apache/clerezza","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vprokopchuk256.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-03-09T13:47:04.000Z","updated_at":"2022-09-27T03:54:42.000Z","dependencies_parsed_at":"2022-07-07T11:33:16.254Z","dependency_job_id":null,"html_url":"https://github.com/vprokopchuk256/mv-core","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vprokopchuk256%2Fmv-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vprokopchuk256%2Fmv-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vprokopchuk256%2Fmv-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vprokopchuk256%2Fmv-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vprokopchuk256","download_url":"https://codeload.github.com/vprokopchuk256/mv-core/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vprokopchuk256%2Fmv-core/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259184731,"owners_count":22818265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","constraints","db-constraints","ror"],"created_at":"2025-02-19T22:20:13.253Z","updated_at":"2025-06-11T02:03:29.248Z","avatar_url":"https://github.com/vprokopchuk256.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/vprokopchuk256/mv-core.svg?branch=master)](https://travis-ci.org/vprokopchuk256/mv-core)\n[![Coverage Status](https://coveralls.io/repos/vprokopchuk256/mv-core/badge.png?branch=master)](https://coveralls.io/r/vprokopchuk256/mv-core?branch=master)\n[![Gem Version](https://badge.fury.io/rb/mv-core.svg)](http://badge.fury.io/rb/mv-core)\n\n# Define validations in database and use them in model\n\nProject ```Migration Validators``` (MV) makes it possible for RoR developer to define validations directly in db and then bubble them up to model so they available as normal ActiveModel::Validations there. And all that without code duplication.\n\n**WARNING** Versions lower than 2.0 are not supported anymore. As results, rails v.3 or older are not supported either.\n\n# Abbreviations\n\nMV - Migration Validators Projects. All gems that belongs to that project are prefixed with mv-*\n\n#Table Of Contents\n* [Why Migration Validators](#why-migration-validators)\n* [How It Works](#how-it-works)\n* [Examples](#examples)\n* [Installation](#installation)\n  * [PostgreSQL](#postgresql)\n  * [MySQL](#mysql)\n  * [SQLite](#sqlite)\n* [Integration with ActiveRecord](#integration-with-activerecord)\n* [SchemaRb](#schemarb)\n* [Tasks](#tasks)\n* [Drivers](#drivers)\n* [Version History](#version history)\n* [Contributing](#contributing)\n\n# Why `Migration Validators`\n\nIt's commonly accepted in RoR community to ignore database constraints and define data validations in ActiveModel. In most cases such approach is perfectly acceptable and allows developer to concentrate on business logic rather than on writing database - specific code.\n\nBut when your application grows significantly then possibility of the data error with such approach became more tangible. Data consistency could be violated in many ways: directly ( with db console for ex ), as result of some error in the code, by other application if database is shared.\n\nDB constraints could help in such case. But there are several reasons why they are not widely spread in RoR: such constraints are DB - specific in most cases and their management is quite tricky.\n\nThe goal of the `Migration Validators` project is to resolve those problems and make DB constraints management straightforward\n\n# How It Works\n\n`Migration Validators` project uses 3 database constructs to define validations: ```trigger```, ```check constraint```, ```index```\n\nMost of the validations could be defined in several ways: as condition inside trigger, as condition inside check constraint or as index ( for ```uniqueness```)\n\nIn most cases developer can select how and where validation should be implemented. By default most optimal way is proposed.\n\nFor example: ```uniqueness``` validation is defined as unique index by default. But developer can select other way - trigger of check constraint. Each way has own advantages and disadvantages\n\n# Examples\n\n  Create new table:\n\n  ```ruby\n  def change\n    create_table do |t|\n      t.string :str_column, validates: { uniqueness: :true,\n                                         inclusion: { in: 1..3 }}\n      t.column :column_name, :integer, validates: { exclusion: { in: [1,2,3]}}\n    end\n  end\n  ```\n\n  Modify existing table:\n\n  ```ruby\n  def up\n    change_table do |t|\n      t.change :str_column, :integer, validates: { exclusion: { in: [1,2,3] }}\n      t.validates :column_name, inclusion: { in: 1..3 }\n    end\n  end\n\n  def down\n    change_table do |t|\n      t.change :str_column, :integer, validates: { exclusion: false }\n      t.validates :column_name, inclusion: false\n    end\n  end\n  ```\n\n  Update validation definition:\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, exclusion: { in: [1,2,3] }\n  end\n\n  def down\n    validates :table_name, :str_column, exclusion: false\n  end\n  ```\n\n There are many ways to define desired database constraint. And those ways might vary for each RDBMS. One could define the way how constraint should be\n defined in DB:\n\n  as trigger:\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, uniqueness: { as: :trigger }\n  end\n\n  def down\n    validates :table_name, :str_column, uniqueness: { as: :index }\n  end\n  ```\n\n  as check constraint:\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, uniqueness: { as: :check }\n  end\n\n  def down\n    validates :table_name, :str_column, uniqueness: false\n  end\n  ```\n\n  Also there is possibility to define when validations should occur:\n\n  when new record created:\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, uniqueness: { on: :create }\n  end\n\n  def down\n    validates :table_name, :str_column, uniqueness: false\n  end\n  ```\n\n  or when existing record updated:\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, uniqueness: { on: :update }\n  end\n\n  def down\n    validates :table_name, :str_column, uniqueness: { on: :save }\n  end\n  ```\n\n  And if you need to define some custom validation you can use custom validation (version \u003e= 2.1 is required):\n\n  ```ruby\n  def up\n    validates :table_name, :str_column,\n                      custom: { statement: 'LENGTH(TRIM({str_column})) \u003e 10',\n                                on: :update }\n  end\n\n  def down\n    validates :table_name, :str_column, custom: false\n  end\n  ```\n\n  as result only values with length greater than 10 will be allowed and that condition will be implemented inside ON UPDATE trigger\n\n  Almost all validations supports shorter notation (simplification) that is not compatible with ActiveRecord validation but much shorter (version \u003e= 2.1 is required):\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, uniqueness: true, presence: true\n  end\n\n  def down\n    validates :table_name, :str_column, uniqueness: false, presence: false\n  end\n  ```\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, length: 1..3\n  end\n\n  def down\n    validates :table_name, :str_column, length: false\n  end\n  ```\n\n  ```ruby\n  def up\n    validates :table_name, :str_column, custom:\n                           'LENGTH(TRIM({str_column})) \u003e 10'\n  end\n\n  def down\n    validates :table_name, :str_column, custom: false\n  end\n  ```\n\n  Supported validators, simplification and their properties might vary from one db driver to another. See detailed properties description in correspondent [driver](#drivers) section.\n\n# Installation\n\n`mv-core` is a set of core classes that are used everywhere across `Migration Validators` project gems.\n\nThis gem is not intended to be installed directly and referenced from within the application. You should rather install appropriate driver.\n\n### PostgreSQL:\n\n  ```\n  gem install mv-postgresql\n  ```\n\n### MySQL:\n\n  ```\n  gem install mv-mysql\n  ```\n\n### SQLite:\n\n  ```\n  gem install mv-sqlite\n  ```\n\n# Integration With ActiveRecord\n\nYou can level up validations that are defined in DB to your model using `enforce_migration_validations` method.\n\nExample:\n\nmigration:\n\n```ruby\n  def change\n    create_table :posts do |t|\n      t.string :title, presence: { message: \"can't be blank\", as: :trigger }\n    end\n  end\n```\n\nmodel:\n\n```ruby\n  class Post \u003c\u003c ActiveRecord::Base\n    enforce_migration_validations\n  end\n```\n\nconsole:\n\n```ruby\n  p = Post.new(title: nil)\n\n  p.valid?\n  =\u003e false\n\n  p.errors.full_messages\n  =\u003e [\"Title can't be blank\"]\n```\n\n# SchemaRb\n\n  All validations that you've defined are dumped to schema.rb automatically:\n\n  in migration:\n\n```ruby\n  def change\n    create_table :posts do |t|\n      t.string :title, presence: { message: \"can't be blank\", as: :trigger }\n    end\n  end\n```\n\nin 'schema.rb':\n\n```ruby\n  validates(:posts, :title,\n                    presence: { message: \"can't be blank\", as: :trigger})\n```\n\n# Tasks\n\n  Show all constraints on the specified tables:\n\n  ```ruby\n  bundle exec rake mv:show_constraints['table_name other_table_name']\n  ```\n\n  or show all constraints are created in migrations:\n\n  ```ruby\n  bundle exec rake mv:show_constraints\n  ```\n\n  Remove all constraints on the specified tables:\n\n  ```ruby\n  bundle exec rake mv:delete_constraints['table_name other_table_name']\n  ```\n\n  or remove all constraints are created in migrations:\n\n  ```ruby\n  bundle exec rake mv:delete_constraints\n  ```\n\n  Create / restore / update constraints on the specified tables:\n\n  ```ruby\n  bundle exec rake mv:create_constraints['table_name other_table_name']\n  ```\n\n  or do it for the all tables:\n\n  ```ruby\n  bundle exec rake mv:create_constraints\n  ```\n\n  Remove all constraints and drop `migration_validators` table:\n\n  ```ruby\n  bundle exec rake mv:uninstall\n  ```\n\n  Restore `migrations_validators` table:\n\n  ```ruby\n  bundle exec rake mv:install\n  ```\n\n# Drivers\n\nCurrently there are drivers for MySQL, PostgreSQL and SQLite RDBMS\n\nSo - see detailed info here:\n\n* PostgreSQL: https://github.com/vprokopchuk256/mv-postgresql\n* MySQL: https://github.com/vprokopchuk256/mv-mysql\n* SQLite: https://github.com/vprokopchuk256/mv-sqlite\n\n## Version History\n\n**(2.0.0)** (17 Jan, 2015)\n\n* Completely rewritten. Migrated to Ruby 2.0 and RoR 4\n\n**(2.1.0)** (22 Jan, 2015)\n\n* Custom validation\n\n**(2.2.0)** (28 Jan, 2015)\n\n* Integration with ActiveRecord\n\n**(2.2.1)** (20 Jul, 2015)\n\n* Fix issue with invalid parameters number in `add_column` and `change_column` methods\n\n**(2.2.2)** (23 Nov, 2015)\n\n* Do not camel case column name in error message\n\n**(2.2.3)** (23 Feb, 2016)\n\n* Suppress exception while running db:schema:load\n\n**(2.2.4)** (12 Sep, 2016)\n\n* Escape single quotes in the custom validation statement body\n\n## Contributing\n\n* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet\n* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it\n* Fork the project\n* Start a feature/bugfix branch\n* Commit and push until you are happy with your contribution\n* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.\n* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvprokopchuk256%2Fmv-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvprokopchuk256%2Fmv-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvprokopchuk256%2Fmv-core/lists"}