Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Let's say we have the following schema:
- ```.rb
- create_table "users", force: :cascade do |t|
- t.string "name"
- t.string "email"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- end
- create_table "messages", force: :cascade do |t|
- t.string "content"
- t.integer "sender_id"
- t.integer "recipient_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- end
- create_table "tracks", force: :cascade do |t|
- t.string "name"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- end
- ```
- And let's say we want something like the following associations:
- ```.rb
- class User < ActiveRecord::Base
- has_many :tracks # doesn't work yet
- has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
- has_many :received_messages, class_name: "Message", foreign_key: "recipient_id"
- end
- class Message < ActiveRecord::Base
- has_many :tracks # doesn't work yet
- belongs_to :sender, class_name: "User", foreign_key: "sender_id"
- belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
- end
- ```
- As is, this won't work, since the `tracks` table doesn't store a `message_id` column or a `user_id` column. What we can do is add a new helper table, `trackings`, that stores three things:
- 1. A `track_id`, which points to a specific track.
- 2. A `tracker_id`, which points to a...
- 3. `tracker_type` type of owner.
- Just to make the terminology clear, a `tracking` witnesses that a `tracker` has (owns, is listening to...) a track. For example, a row that looks like `(123, 19, "User")` indicates that track 123 is one of User 19's tracks.
- Here's a suitable migration:
- ```.rb
- class CreateTrackings < ActiveRecord::Migration
- def change
- create_table :trackings do |t|
- t.references :track, index: true, foreign_key: true
- t.references :tracker, polymorphic: true, index: true
- t.timestamps null: false
- end
- end
- end
- ```
- Saying `t.references :tracker, polymorphic: true` gives us the `tracker_id` and `tracker_type` columns automatically.
- Now that we have the `trackings` helper table, we can fix our original `has_many` relationships:
- ```.rb
- class User < ActiveRecord::Base
- has_many :trackings, as: :tracker, dependent: :destroy
- has_many :tracks, through: :trackings
- has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
- has_many :received_messages, class_name: "Message", foreign_key: "recipient_id"
- end
- class Message < ActiveRecord::Base
- has_many :trackings, as: :tracker, dependent: :destroy
- has_many :tracks, through: :trackings
- belongs_to :sender, class_name: "User", foreign_key: "sender_id"
- belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
- end
- class Track < ActiveRecord::Base
- has_many :trackings, dependent: :destroy
- end
- ```
- In words, Users and Messages both have a polymorphic `has_many` relationship to `trackings`, and they then both have a `has_many` relationship to `tracks` `:through` the first relationship :)
- Now we can do things like
- ```.rb
- > hot_track = Track.create(name: "Hot Track")
- > me = User.find_by(email: my_email)
- > me.tracks << hot_track
- > you = User.find_by(email: your_email)
- > you.tracks.create(name: "My Jam")
- ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement