{"id":15064649,"url":"https://github.com/nicksterious/database_logic","last_synced_at":"2026-01-02T09:22:04.167Z","repository":{"id":49290331,"uuid":"378468455","full_name":"nicksterious/database_logic","owner":"nicksterious","description":"A gem that helps managing your database-level logic within your Rails apps.","archived":false,"fork":false,"pushed_at":"2023-06-19T11:50:14.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-23T07:04:57.423Z","etag":null,"topics":["activerecord","rails","ruby-on-rails","sql"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/database_logic","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicksterious.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-06-19T17:26:40.000Z","updated_at":"2023-06-19T11:03:15.000Z","dependencies_parsed_at":"2022-08-28T19:51:27.864Z","dependency_job_id":"d60201b2-ddaa-4c6a-841b-7d5d1dbdcc42","html_url":"https://github.com/nicksterious/database_logic","commit_stats":null,"previous_names":["freecrap/database_logic"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicksterious%2Fdatabase_logic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicksterious%2Fdatabase_logic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicksterious%2Fdatabase_logic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicksterious%2Fdatabase_logic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicksterious","download_url":"https://codeload.github.com/nicksterious/database_logic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243790999,"owners_count":20348385,"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","rails","ruby-on-rails","sql"],"created_at":"2024-09-25T00:23:31.051Z","updated_at":"2026-01-02T09:22:04.143Z","avatar_url":"https://github.com/nicksterious.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DatabaseLogic\n\nRight, database layer logic is a big no-no in the Rails community.\n\nBut if you're building something serious, sooner or later you will need to break the rules - none of these frameworks are silver bullets despite the almost-fanatism behind their doctrines. \n\nThere are several gems out there that come up with different solutions, yet they are very opinionated and sometimes get in the way. This simple gem tries to solve these issues with a few simple tasks and generators.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'database_logic'\n```\n\nAnd then execute:\n\n    $ bundle install\n\nOr install it yourself as:\n\n    $ gem install database_logic\n\n\n## Quick howto\n\n`rails g database_logic:view users_full`\n\n`rails g database_logic:trigger CreateInitialSnapsho after insert users` \n\n`rails g database_logic:trigger DeleteUserData before delete users`\n\n`rails g database_logic:function SuperFunc`\n\n`rails g database_logic:procedure CleanupLogTables`\n\n`rails g database_logic:event Daily 24 hour`\n\n`rails g database_logic:event hourly_task 60 minute`\n\n\n## Usage / walkthrough\n\nFirst, let's try creating a view. For this, we will need an User model, as follows:\n\n`rails g model User first_name:string last_name:string balance_in_cents:integer address:string city:string`\n\nthis will generate:\n\n```ruby\n# app/db/migrate/20210619153721_create_users.rb\nclass CreateUsers \u003c ActiveRecord::Migration[6.0]\n  def change\n    create_table :users do |t|\n        t.string :first_name\n        t.string :last_name\n        t.integer :balance_in_cents\n        t.string :address\n        t.string :city\n        t.timestamps\n    end\n  end\nend\n```\n\nSo far so good! Let's apply our changes:\n\n`rails db:migrate`\n\nNow let's assume we want a view that shows users' first name and last name merged into `full_name`, so we will use the view generator to create our first view file:\n\n`rails g database_logic:view users_full`\n\nThis will generate:\n\n```\n# app/sql/views/20210519160509_users_full.sql\n# ... some default garbage from a template...\n```\nLet us edit this file, delete the gibberish and add our view SQL:\n\n```\ncreate or replace view [DB].users_full as\n select concat(first_name, ' ', last_name) as full_name, balance_in_cents/100 as balance, concat(address, ' ', city) as full_address from [DB].users;\n```\n\nAfter saving the SQL file let's apply our changes:\n\n`rake database_logic:views:create`\n\n```\nMariaDB [app_dev]\u003e describe users_full;\n+--------------+---------------+------+-----+---------+-------+\n| Field        | Type          | Null | Key | Default | Extra |\n+--------------+---------------+------+-----+---------+-------+\n| full_name    | varchar(511)  | YES  |     | NULL    |       |\n| balance      | decimal(14,4) | YES  |     | NULL    |       |\n| full_address | varchar(511)  | YES  |     | NULL    |       |\n+--------------+---------------+------+-----+---------+-------+\n```\n\nSo far so good! At this point we might not want to have to run a rake task after each addition/change, so we want to .enhance the db:migrate task as follows:\n\n```ruby\n# lib/tasks/dblogic.rake\n\n# on drop, drop SQL logic too\nRake::Task[\"db:drop\"].enhance [\"database_logic:drop\"]\n\n# on migration, re-create all SQL logic\nRake::Task[\"db:migrate\"].enhance do\n    Rake::Task[\"database_logic:recreate\"].execute\nend\n```\n\nBut in real life, users have Transactions, so let's also create a Transaction model, as follows:\n\n`rails g model Transaction user_id:integer amount_in_cents:integer kind:string`\n\nthis will generate:\n\n```ruby\n# app/db/migrate/20210619153732_create_transactions.rb\nclass CreateTransactions \u003c ActiveRecord::Migration[6.0]\n  def change\n    create_table :transactions do |t|\n        t.integer :user_id\n        t.integer :amount_in_cents\n        t.string :kind\n      t.timestamps\n    end\n  end\nend\n```\n\nAnd now, let's say we want our \"balance\" column to update _on the database side_ whenever we add Transactions. Without bloating our models with AR hooks/callbacks, and without database inconsistencies caused by the delays that plague db to app communication, that is.\n\nFirst, we will create a trigger:\n\n`rails g database_logic:trigger after insert transactions`\n\nThis will generate:\n```\n# app/sql/triggers/20213619173650_update_balance.sql\n# ... some default garbage from a template...\n```\n\nWe want to edit this file and add our trigger SQL:\n```\ncreate trigger update_balance after insert on [DB].transactions\nfor each row\n    begin\n        update users set balance_in_cents = balance_in_cents+NEW.amount_in_cents;\n    end;\n```\n\nFinally, let's migrate: `rake db:migrate`. Our `rake db:migrate` enhancement automagically ran our SQL so we're good to go!\n\nLet's try it out, in a rails console (`rails c`) \n```\n2.5.5 :007 \u003e User.first.balance_in_cents;\n =\u003e 0\n\n2.5.5 :008 \u003e Transaction.create(user_id: 1, amount_in_cents: 123, kind: \"Transfer\")\n =\u003e #\u003cTransaction id: 81, user_id: 1, amount_in_cents: 123, kind: \"Transfer\", created_at: \"2021-06-19 18:05:32\", updated_at: \"2021-06-19 18:05:32\"\u003e\n2.5.5 :009 \u003e User.first.balance_in_cents;\n =\u003e 123\n```\n\nNoice! \n\nFunctions, procedures and events work in the same manner, you can go on and play with them on your own!\n\n## Gotchas\n\nYou may want to use alphanumeric names for your SQL function/... names, the generators try normalizing them but just in case, try not to use names like _$up'erk3wl ha{er#name_ or similar gibberish.\n\n\n## Roadmap\n* specs\n* a way to select which database to use, when there are multiple\n\n\n## Contributing\n\nBug reports are welcome and pull requests are more than welcome on GitHub at https://github.com/freecrap/database_logic. Contributors are expected to adhere to the [code of conduct](https://github.com/freecrap/database_logic/blob/master/CODE_OF_CONDUCT.md). I haven't edited this file yet so until I do please don't be naughty.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicksterious%2Fdatabase_logic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicksterious%2Fdatabase_logic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicksterious%2Fdatabase_logic/lists"}