Advertisement
Guest User

Untitled

a guest
Jul 4th, 2015
237
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.17 KB | None | 0 0
  1. Let's say we have the following schema:
  2.  
  3. ```.rb
  4. create_table "users", force: :cascade do |t|
  5. t.string "name"
  6. t.string "email"
  7. t.datetime "created_at", null: false
  8. t.datetime "updated_at", null: false
  9. end
  10.  
  11. create_table "messages", force: :cascade do |t|
  12. t.string "content"
  13. t.integer "sender_id"
  14. t.integer "recipient_id"
  15. t.datetime "created_at", null: false
  16. t.datetime "updated_at", null: false
  17. end
  18.  
  19. create_table "tracks", force: :cascade do |t|
  20. t.string "name"
  21. t.datetime "created_at", null: false
  22. t.datetime "updated_at", null: false
  23. end
  24. ```
  25.  
  26. And let's say we want something like the following associations:
  27.  
  28. ```.rb
  29. class User < ActiveRecord::Base
  30. has_many :tracks # doesn't work yet
  31.  
  32. has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
  33. has_many :received_messages, class_name: "Message", foreign_key: "recipient_id"
  34. end
  35.  
  36. class Message < ActiveRecord::Base
  37. has_many :tracks # doesn't work yet
  38.  
  39. belongs_to :sender, class_name: "User", foreign_key: "sender_id"
  40. belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
  41. end
  42. ```
  43.  
  44. 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:
  45.  
  46. 1. A `track_id`, which points to a specific track.
  47. 2. A `tracker_id`, which points to a...
  48. 3. `tracker_type` type of owner.
  49.  
  50. 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.
  51.  
  52. Here's a suitable migration:
  53.  
  54. ```.rb
  55. class CreateTrackings < ActiveRecord::Migration
  56. def change
  57. create_table :trackings do |t|
  58. t.references :track, index: true, foreign_key: true
  59. t.references :tracker, polymorphic: true, index: true
  60.  
  61. t.timestamps null: false
  62. end
  63. end
  64. end
  65. ```
  66.  
  67. Saying `t.references :tracker, polymorphic: true` gives us the `tracker_id` and `tracker_type` columns automatically.
  68.  
  69. Now that we have the `trackings` helper table, we can fix our original `has_many` relationships:
  70.  
  71. ```.rb
  72. class User < ActiveRecord::Base
  73. has_many :trackings, as: :tracker, dependent: :destroy
  74. has_many :tracks, through: :trackings
  75.  
  76. has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
  77. has_many :received_messages, class_name: "Message", foreign_key: "recipient_id"
  78. end
  79.  
  80. class Message < ActiveRecord::Base
  81. has_many :trackings, as: :tracker, dependent: :destroy
  82. has_many :tracks, through: :trackings
  83.  
  84. belongs_to :sender, class_name: "User", foreign_key: "sender_id"
  85. belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
  86. end
  87.  
  88. class Track < ActiveRecord::Base
  89. has_many :trackings, dependent: :destroy
  90. end
  91. ```
  92.  
  93. 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 :)
  94.  
  95. Now we can do things like
  96.  
  97. ```.rb
  98. > hot_track = Track.create(name: "Hot Track")
  99. > me = User.find_by(email: my_email)
  100. > me.tracks << hot_track
  101. > you = User.find_by(email: your_email)
  102. > you.tracks.create(name: "My Jam")
  103. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement