Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/igorkasyanchuk/mechanical

All models in a single table, new attributes without migrations. Works like regular AR model
https://github.com/igorkasyanchuk/mechanical

Last synced: about 2 months ago
JSON representation

All models in a single table, new attributes without migrations. Works like regular AR model

Awesome Lists containing this project

README

        

# Mechanical

[![RailsJazz](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/my_other.svg?raw=true)](https://www.railsjazz.com)
[![https://www.patreon.com/igorkasyanchuk](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/patron.svg?raw=true)](https://www.patreon.com/igorkasyanchuk)

Simple gem which allows to store multiple models in a single table in DB (Postgres only). It's using STI and Postgres JSONB data type.

The whole schema is defined in one initializer file, and new attributes could be easily added just by adding new attribute in that file. So you don't need to create a migration.

## Usage

- add in the Gemfile `gem "mechanical"`
- execute `bundle install`
- execute `rails g mechanical initializer`
- execute `rake db:migrate`
- edit `config/initializers/mechanical.rb` and define your schema
- start app `rails s`
- you can use models `Mechanical::Model::MODEL_NAME` in you app like a regular model.

You need to define attribute and it's type (it's importan to check this gem: https://github.com/madeintandem/jsonb_accessor).
In addition you can specify relations, validations, add instance or class methods. Behavior is the same as with AR model.

```ruby

Mechanical.setup do |config|

model "Account" do
field :name, type: :string
field :balance, type: :integer

has_many :posts

validates :name, presence: true
validates :balance, numericality: true
end

model "Post" do
field :title, type: :string
field :description, type: :text
field :published_on, type: :date
field :account_id, type: :integer
field :active, type: :boolean, default: true

belongs_to :account, optional: true

has_one_attached :file

validates :title, presence: true

scope :active, -> { jsonb_where(:mechanical_data, active: true) }

after_create :say_hello

add_methods do
def self.total_posts
self.count
end

def title_uppercase
title&.upcase
end

def say_hello
puts "HELLO FROM initializer #{self}"
end
end
end

end
```

After Installation you can do the following:

```ruby
post = Mechanical::Model::Post.create(title: "Hello world", description: "this is description")
post.persisted? # true

post.title # "Hello world"
post.description # "this is description"

# for querying use: https://github.com/madeintandem/jsonb_accessor

Mechanical::Model::Post.create(title: "ABC", description: "this is description")
Mechanical::Model::Post.create(title: "TRE", description: "this is second description")
Mechanical::Model::Account.create(name: "XYZ", balance: 100)
Mechanical::Model::Account.create(name: "MTR", balance: 200)
Mechanical::Model::Post.jsonb_where(:mechanical_data, { title: 'ABC' }).count # 1
Mechanical::Model::Account.mechanical_data_where(balance: { greater_than_or_equal_to: 150 }).count # 1
Mechanical::Model::Account.mechanical_data_where(balance: 10..250).count # 2
```

If you are building form and want to use this model you can do it same way as using regular model:

Example of very simple controller:

```ruby
def index
@post = Mechanical::Model::Post.new
end

def submit_post
@post = Mechanical::Model::Post.new(params.require(:post).permit!)
@post.user = User.first
@post.save
if @post.save
redirect_to root_path
else
@posts = Mechanical::Model::Post.all
render :index
end
end
```

View:

```erb

<%= simple_form_for @post, url: submit_post_url, html: { novalidate: true } do |f| %>
<%= f.error_messages %>
<%= f.association :account %>
<%= f.input :title %>
<%= f.input :description %>
<%= f.input :published_on %>
<%= f.input :file %>
<%= f.input :active %>


<%= f.submit %>
<% end %>

```

As you can see it supports active storage.

## Installation
Add this line to your application's Gemfile:

```ruby
gem 'mechanical'
```

And then execute:
```bash
$ bundle
```
## Contributing

You are welcome to contribute.

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).

[](https://www.railsjazz.com/?utm_source=github&utm_medium=bottom&utm_campaign=mechanical)