Make your ActiveRecord model as a item, it can be child or parent of self-modle or other-model
When will you need this gem?
Think about you are using PostgreSQL database, you just want to simplely store some unusually-query data into one table, put various files into one jsonb filed, record many have some child records, or parent records, such as a Car has many accessories: 4 Wheels, 3 Chairs, and a Wheel has one Tyre, 5 Screws. I don't care how to store them, just care about their relations, so now let's make this with Itemable
:
- Setup
Itemable
- Create Models
Car
,Wheel
,Chair
,Tyre
,Screw
- Create relations to each model
Installation
Add this line to your application's Gemfile:
gem 'itemable'
And then execute below to create tables itemable_items
and itemable_item_relations
:
$ rails g itemable:migration
$ rake db:migrate
Usage
Create Car
modle
$ rails g model car name
Update app/models/car.rb
:
class Car < ActiveRecord::Base
acts_as_itemable
has_many_items :wheels, dependent: :destroy
has_many_items :chairs, dependent: :destroy
end
-
acts_as_itemable
makesCar
has all feature ofItemable
-
has_many_items :wheels
declares a car has many wheels -
has_many_items :chairs
declares a car has many chairs
Create Wheel
model without db migration:
Add app/models/wheel.rb
class Wheel < ActiveRecord::Base
acts_as_itemable sti: true
belongs_to_item :car
has_many_items :screws, dependent: :destroy
has_one_item: :tyre, dependent: :destroy
end
-
acts_as_itemable sti: true
,sti = true
meansWheel
is a single table inherited Model, will get records from tableitemable_items
-
belongs_to_item :car
declares wheel belongs to car -
has_one_item: :tyre
declares wheel has only one tyre
Add app/models/chair.rb
class Chair < ActiveRecord::Base
acts_as_itemable sti: true
belongs_to_item :car
end
Add app/models/tyre.rb
class Tyre < ActiveRecord::Base
acts_as_itemable sti: true
belongs_to_item :wheel
end
Add app/models/screw.rb
class Screw < ActiveRecord::Base
acts_as_itemable sti: true
belongs_to_item :wheel
end
Now everything is ready, let store/query data
car = Car.create
4.times do
car.wheels << Wheel.create
end
3.times do
car.chairs << Chair.create
end
wheel = Wheel.first
wheel.tyre = Tyre.create
5.times do
wheel.screws << Screw.create
end
car.reload
car.item_children.count => 7
car.item_children.map(&:child)
=> [#<Wheel:0x007f86ba65f930 id: 16, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86ba677fa8 id: 17, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86ba685568 id: 18, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86ba69c038 id: 19, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Chair:0x007f86ba6cd0e8 id: 20, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>,
#<Chair:0x007f86ba6e4e28 id: 21, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>,
#<Chair:0x007f86ba706c58 id: 22, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>]
car.wheels.count => 4
=> [#<Wheel:0x007f86c018b8e0 id: 16, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86c018b750 id: 17, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86c018b5c0 id: 18, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>,
#<Wheel:0x007f86c018b430 id: 19, type: "Wheel", created_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:18 UTC +00:00>]
car.chairs.count => 3
=> [#<Chair:0x007f86be2baab0 id: 20, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>,
#<Chair:0x007f86be2ba830 id: 21, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>,
#<Chair:0x007f86be2ba538 id: 22, type: "Chair", created_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:22 UTC +00:00>]
wheels = car.wheels
wheels[0].item_children.count => 6
wheels[0].item_children.map(&:child)
=> [#<Tyre:0x007f86be44f290 id: 23, type: "Tyre", created_at: Fri, 07 Apr 2017 04:53:33 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:33 UTC +00:00>,
#<Screw:0x007f86be46e0f0 id: 24, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86be47cf60 id: 25, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86be497d38 id: 26, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86be4a6ba8 id: 27, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86be4b59f0 id: 28, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>]
wheels[0].tyre
=> #<Tyre:0x007f86b8fb04c8 id: 23, type: "Tyre", created_at: Fri, 07 Apr 2017 04:53:33 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:33 UTC +00:00>
wheels[0].screws.count => 5
=> [#<Screw:0x007f86b833c750 id: 24, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86b833c570 id: 25, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86b833c3e0 id: 26, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86b833c250 id: 27, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>,
#<Screw:0x007f86b833c0c0 id: 28, type: "Screw", created_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:53:49 UTC +00:00>]
wheels[1].tyre => nil
wheels[1].tyre = Tyre.create
=> #<Tyre:0x007f86bbb8e450 id: 29, type: "Tyre", created_at: Fri, 07 Apr 2017 04:58:05 UTC +00:00, updated_at: Fri, 07 Apr 2017 04:58:05 UTC +00:00>
wheels[1].item_children.count => 1
See, it's so easy to build model relations
Advanced Usage
acts_as_itemable
has following options:
-
sti
:true
orfalse
-
children
:true
orfalse
-
true
generates associationitem_children
, then supporthas_many_items
-
false
does nothing
-
-
child
:true
orfalse
-
true
generates associationitem_child
, then supporthas_one_item
-
false
does nothing
-
-
parents
:true
orfalse
-
true
generates associationitem_parents
, then supportbelongs_to_items
-
false
does nothing
-
-
parent
:true
orfalse
-
true
generates associationitem_parents
, then supportbelongs_to_item
-
false
does nothing
-
options of has_many_items
, has_one_item
, belongs_to_items
, belongs_to_item
are the same to has_many
or belongs_to
Test
rake
Contributing
Contribution directions go here.
License
The gem is available as open source under the terms of the MIT License.