WARNING: This gem is a work in progress and hasn't released yet.
This plugin implements alternative way to do has_and_belongs_to_many
association in Rails using the power of PostgreSQL arrays. In many cases when you just need acts_as_list or acts-as-taggable-on functionality the traditional approach using many-to-many with join tables is unnecessary. We can just store integer array of ids.
Suppose we have a playlist that contains many videos. One video can be included in many playlists. It's a classic many-to-many situation but we implement it differently.
# db/migrate/20141027125227_create_playlist.rb
class CreatePlaylist < ActiveRecord::Migration
def change
create_table :playlists do |t|
t.integer :video_ids, array: true # adding array fields works only starting from Rails 4
t.index :video_ids, using: :gin # we add GIN index to speed up specific queries on array
end
end
end
# app/models/playlist.rb
class Playlist < ActiveRecord::Base
has_array_of :videos # by convention, it assumes that Post has a video_ids array field
end
# app/models/video.rb
class Video < ActiveRecord::Base
belongs_to_array_in_many :playlists # optional
end
Now we can work with videos
like with regular array. It will correctly proxy all changes to video_ids
field.
playlist = Playlist.find(1)
playlist.videos = [video1,video2] # playlist.video_ids = [1, 2]
playlist.videos[0] = video3 # playlist.video_ids[0] = 3
playlist.videos.insert(1, video4) # playlist.video_ids = [3, 4, 2]
playlist.videos.delete_at(1) # playlist.video_ids = [3, 2]
playlist.videos.pop # playlist.video_ids = [3]
# ... and so on
video3.playlists
# => [playlist]
has_array_of
also adds some search scopes:
Playlist.with_videos_containing(video1, video2)
Playlist.with_videos_contained_in(video1, video2, video3, video4, ...)
Playlist.with_any_videos_from(video1, video2, video3, video4, ...)
Anything like associated lists or arrays can be implemented such way. Now, the more typical example:
class Tag; end
class Post
has_array_of :tags
end
Tags, arrays, lists — they're all the same!
- Fork it
% bundle install
% createdb has_array_of_test
% bundle exec rspec
- ...
- Make pull request!