README.markdown in acts-as-joinable-0.0.1.7 vs README.markdown in acts-as-joinable-0.0.6
- old
+ new
@@ -1,82 +1,99 @@
# ActsAsJoinable
-It extends the functionality of `has_and_belongs_to_many`, conventionalizing common use cases.
+Like has_many_polymorphs but easier. Can handle double polymorphic associations with single table inheritance from the join model.
-## Usage
+## Install
-### Install
-
sudo gem install acts-as-joinable
-### Add Relationships
+## Usage
-Say you have `Post` and `Asset` models. If each `has_many` of each other `through` some join model, you can write it as such:
+### Dry Assocations with Zero Dependencies
- class Post < ActiveRecord::Base
- acts_as_joinable_on :assets, :layouts, :tags, :slugs
+Here's what you would write:
+
+ class Content < ActiveRecord::Base
+ joins :assets
+ joins :images
+ joins_one :cover_image, :source => :image
end
- class Asset < ActiveRecord::Base
- acts_as_joinable
+ class Page < Content
+ joins :children, :as => :parent, :source => :content
+ joins :parents, :as => :child, :source => :content
end
-That is a replacement for the longer (and non-polymorphic):
-
- class Post < ActiveRecord::Base
- has_and_belongs_to_many :assets
+ class Post < Content
+ joins :parents, :as => :child, :source => :page
end
class Asset < ActiveRecord::Base
- has_and_belongs_to_many :posts
+ joinable
end
+
+ class Image < Asset
+
+ end
+
+Here's how you'd use it:
-## Why
+ page = Page.create!(:title => "Home Page")
+ post = Post.create!(:title => "My first blog post")
+ image = Image.create!(:src => "http://imgur.com/123123.png")
+
+ page.children << post
+ post.cover_image = image
+
+ assert_equal post, page.children.first
+ assert_equal image, post.images.first
+ assert_equal image, post.assets.first
+
+You can also create a simple group membership system no problem:
-Many-to-many relationships end up requiring the same features 99% of the time:
+ class User < ActiveRecord::Base
+ joins :groups, :as => :child, :context => :membership
+ end
-1. Join Table that keeps track of `context`
- - [ActsAsTaggableOn](http://github.com/mbleigh/acts-as-taggable-on/blob/master/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb)
- - ActsAsAuthorized
- - [Preferences](http://github.com/pluginaweek/preferences/blob/master/generators/preferences/templates/001_create_preferences.rb)
- - [FriendlyId](http://github.com/norman/friendly_id/blob/ca9821192c8c3c4e81a938603151645c7cbe1470/generators/friendly_id/templates/create_slugs.rb)
+ class Group < ActiveRecord::Base
+ joins :members, :context => :membership, :source => :user
+ joins_one :admin, :context => :membership, :value => :admin, :source => :user
+ joins :board_of_directors, :context => :membership, :value => :board, :source => :user
+ end
-It looks like this:
+ basic_member = User.create!(:position => "I'm an employee")
+ board_member = User.create!(:position => "I'm on the board")
+ company = Group.create!(:name => "A Company")
+ company.members << basic_member
+ company.board_of_directors << board_member
+
+ assert_equal 2, company.members.length
+ assert_equal 1, company.board_of_directors
+
+### What's it doing?
+
+First, it has a generic join model. All join models are the same in the end, so there is no need to create extra tables for each. Maybe when you get 10,000,000 records you'll need to start creating tables for specific joins, but you don't need that by default. It increases the complexity of your application unnecessarily which makes it harder to extend and manage.
+
+Instead, this creates a single join model that will solve for most of your cases (if there is a case it doesn't solve for, I'd love to know, it solves all of mine).
+
+Here's the table for the built-in `Relationship` model:
+
create_table :relationships do |t|
t.references :parent, :polymorphic => true
t.references :child, :polymorphic => true
t.string :context
+ t.string :value
+ t.integer :position
t.timestamps
end
-
-## Alternatives
-
-- [ActsAsRelationable](http://github.com/winton/acts_as_relationable)
-
-## Examples
-
-If you would like to define accessors that scope the relationship based on the `context` attribute of the `Relationship` model, you can do this:
-
- class Post < ActiveRecord::Base
- acts_as_joinable_on :assets, :scopes => [:featured, :thumb]
- end
- @post = Post.new
- @post.featured_assets << Asset.first
-
-If you need more fine-grained control over each relationship scope, you can use a block:
+The features are:
- class Post < ActiveRecord::Base
- acts_as_joinable_on :tags, :assets
- end
-
- @post = Post.new
- @post.featured_image = Image.first
- @post.thumbnails = Image.all
-
-The goal of this is to make it so you never have to create migrations or new classes, or rewrite the same code over and over again. Instead, you can just define `scopes` for cherry-picking the habtm items you'd like.
+1. **Double sided polymorphic associations**. Which means you can tie any object to any other object.
+2. Built-in relationship directionality, similar to a **Directed Acyclic Graph**. So you can say the `Post` is `parent` of `Image`, since you usually attach an Image to a Post (not the other way around), so `Image` is `child` of `Post`. This means you have some sort of built in _hierarchy_.
+3. **Context**. You can create many-to-many relationships between the same models and call them different things. This is roughly equivalent to creating STI join models. This is useful for creating something like organizing `Users` of a `Group` into `Roles`.
+4. **Position**. You can sort the objects by relationship in primitive ways.
-Has 2 key properties on the join model that are pretty common:
+You can always add columns to the relationship table, but the foundation is set.
-- context: what the meaning of the join is
-- position: what position the join is in relation to the context
+<cite>copyright @viatropos 2010</cite>
\ No newline at end of file