What I am trying to do:
I have a blog and want to show related posts below the main post.
class Post < ActiveRecord::Base
has_many :related_posts
has_many :posts, :through => :related_posts
end
And then in the join model/table
class RelatedPost < ActiveRecord::Base
belongs_to :post
end
And of course there is a table called related_posts
with two post_id
columns.
Obviously there are several flaws with this, I'm just not sure how to make this association work in Rails.
They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.
In Ruby on Rails, a polymorphic association is an Active Record association that can connect a model to multiple other models. For example, we can use a single association to connect the Review model with the Event and Restaurant models, allowing us to connect a review with either an event or a restaurant.
That was an interesting question.
I just created a working app for your use case.
post.related_posts will give you all posts related from post, while post.inverse_related_posts will give you all posts related to post.
Here's what my models look like:
class Post < ActiveRecord::Base
has_many :related_posts_association, :class_name => "RelatedPost"
has_many :related_posts, :through => :related_posts_association, :source => :related_post
has_many :inverse_related_posts_association, :class_name => "RelatedPost", :foreign_key => "related_post_id"
has_many :inverse_related_posts, :through => :inverse_related_posts_association, :source => :post
end
class RelatedPost < ActiveRecord::Base
belongs_to :post
belongs_to :related_post, :class_name => "Post"
end
My schema:
ActiveRecord::Schema.define(:version => 20110702194300) do
create_table "posts", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "related_posts", :force => true do |t|
t.integer "post_id"
t.integer "related_post_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Here's a dump of a console session that demonstrating the relationship.
ruby-1.9.2-p180:001:0>> p = Post.create! name: "Hello"
SQL (23.5ms) INSERT INTO "posts" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Sat, 02 Jul 2011 20:03:43 UTC +00:00], ["name", "Hello"], ["updated_at", Sat, 02 Jul 2011 20:03:43 UTC +00:00]]
# => #<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">
ruby-1.9.2-p180:002:0>> p2 = Post.create! name: "World"
SQL (1.0ms) INSERT INTO "posts" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Sat, 02 Jul 2011 20:03:48 UTC +00:00], ["name", "World"], ["updated_at", Sat, 02 Jul 2011 20:03:48 UTC +00:00]]
# => #<Post id: 2, name: "World", created_at: "2011-07-02 20:03:48", updated_at: "2011-07-02 20:03:48">
ruby-1.9.2-p180:003:0>> p.related_posts
Post Load (0.2ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."related_post_id" WHERE "related_posts"."post_id" = 1
# => []
ruby-1.9.2-p180:004:0>> p2.related_posts
Post Load (0.4ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."related_post_id" WHERE "related_posts"."post_id" = 2
# => []
ruby-1.9.2-p180:005:0>> p.related_posts << p2
SQL (0.7ms) INSERT INTO "related_posts" ("created_at", "post_id", "related_post_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sat, 02 Jul 2011 20:04:01 UTC +00:00], ["post_id", 1], ["related_post_id", 2], ["updated_at", Sat, 02 Jul 2011 20:04:01 UTC +00:00]]
# => [#<Post id: 2, name: "World", created_at: "2011-07-02 20:03:48", updated_at: "2011-07-02 20:03:48">]
ruby-1.9.2-p180:006:0>> RelatedPost.all
RelatedPost Load (0.4ms) SELECT "related_posts".* FROM "related_posts"
# => [#<RelatedPost id: 1, post_id: 1, related_post_id: 2, created_at: "2011-07-02 20:04:01", updated_at: "2011-07-02 20:04:01">]
ruby-1.9.2-p180:007:0>> p2.inverse_related_posts
Post Load (0.2ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."post_id" WHERE "related_posts"."related_post_id" = 2
# => [#<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">]
ruby-1.9.2-p180:008:0>> p = Post.first
Post Load (0.5ms) SELECT "posts".* FROM "posts" LIMIT 1
# => #<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">
ruby-1.9.2-p180:009:0>> p2.related_posts << p
SQL (25.7ms) INSERT INTO "related_posts" ("created_at", "post_id", "related_post_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sat, 02 Jul 2011 20:05:29 UTC +00:00], ["post_id", 2], ["related_post_id", 1], ["updated_at", Sat, 02 Jul 2011 20:05:29 UTC +00:00]]
Post Load (0.3ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."related_post_id" WHERE "related_posts"."post_id" = 2
# => [#<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">]
ruby-1.9.2-p180:010:0>> p2.related_posts
# => [#<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">]
ruby-1.9.2-p180:011:0>> exit
Loading development environment (Rails 3.1.0.rc4)
ruby-1.9.2-p180:001:0>> Post.first.related_posts
Post Load (0.3ms) SELECT "posts".* FROM "posts" LIMIT 1
Post Load (0.2ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."related_post_id" WHERE "related_posts"."post_id" = 1
# => [#<Post id: 2, name: "World", created_at: "2011-07-02 20:03:48", updated_at: "2011-07-02 20:03:48">]
ruby-1.9.2-p180:002:0>> Post.last.related_posts
Post Load (0.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT 1
Post Load (0.2ms) SELECT "posts".* FROM "posts" INNER JOIN "related_posts" ON "posts"."id" = "related_posts"."related_post_id" WHERE "related_posts"."post_id" = 2
# => [#<Post id: 1, name: "Hello", created_at: "2011-07-02 20:03:43", updated_at: "2011-07-02 20:03:43">]
You're looking for self referential association.
I suggest you take inspiration here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With