1 2 3 4 5 6 7 8 9 10 11 12 13

пятница, 14 сентября 2012 г.

Ассоциации в Ruby on Rails: полиморфные ассоциации

Разбираем следующий скринкаст Полиморфные ассоциации
Полиморфные ассоциации это специальный тип ассоциаций когда несколько разных таблиц связаны через одну. Допустим у нас есть таблица комментарии. Комментарии могут быть как к товарам, так и к записям блога. Т.е. две таблицы товары и записи блога, связаны с таблицей комментарии через полиморфную ассоциацию. Связь достигается путем того, что в поле id хранится либо id записи блога, к которой оставлен комментарий, либо id товара. Реализуем это на практике. Создадим модель комментарии
rails g model comment

Создадим модель для блога
rails g model blogpost

Создадим миграции
class CreateBlogposts < ActiveRecord::Migration
  def change
    create_table :blogposts do |t|
      t.text :body
      t.string :title
      t.timestamps
    end
  end
end

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :body
      t.integer :user_id
      t.integer :commentable_id
      t.string :commentable_type
      t.timestamps
    end
  end
end

Запустим миграцию
rake db:migrate 

Пропишем связь в моделях
class Item < ActiveRecord::Base

  has_many :positions
  has_many :carts, through: :positions
  has_many :comments, as: :commentable

  attr_accessible :price, :name, :real, :weight, :description

  validates :price, { numericality: { greater_than: 0 }, allow_nil: true }
  validates :name, :description, presence: true

  after_initialize { puts "initialized" } # item.new item.find
  after_create { puts "created" } # item.create
  after_save { puts "saved" } # item.save item.create item.update_attributes
  after_destroy{ puts "deleted" } # item.destroy

end

И в модели blogpost
class Blogpost < ActiveRecord::Base
  attr_accessible :title, :body
  has_many :comments, as: :commentable
end

В модели comment пропишем
class Comment < ActiveRecord::Base
  attr_accessible :body, :user_id, :coomentable_id, :commentable_type
  belongs_to :user
  belongs_to :commentable, polymorphic: true
end
Протестируем в консоли
rails c
1.9.3-p327 :037 >   i = Item.find(19)
  Item Load (0.5ms)  SELECT "items".* FROM "items" WHERE "items"."id" = ? LIMIT 1  [["id", 19]]
initialized
 => #<Item id: 19, price: 200.0, name: "kettle", real: nil, weight: nil, description: "ket", created_at: "2013-03-04 10:24:34", updated_at: "2013-03-04 10:24:34", votes_count: 0>
1.9.3-p327 :038 > u = User.last
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
 => #<User id: 2, login: "Bob", created_at: "2013-03-04 06:50:34", updated_at: "2013-03-04 06:50:34">
1.9.3-p327 :039 > i.comments
  Comment Load (3.0ms)  SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = 19 AND "comments"."commentable_type" = 'Item'
 => []
1.9.3-p327 :040 > i.comments << Comment.new(user_id: u.id, body: "item comment")
   (0.2ms)  begin transaction
  SQL (1.1ms)  INSERT INTO "comments" ("body", "commentable_id", "commentable_type", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?)  [["body", "item comment"], ["commentable_id", 19], ["commentable_type", "Item"], ["created_at", Tue, 05 Mar 2013 12:52:47 UTC +00:00], ["updated_at", Tue, 05 Mar 2013 12:52:47 UTC +00:00], ["user_id", 2]]
   (32.2ms)  commit transaction
 => [#<Comment id: 7, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:52:47", updated_at: "2013-03-05 12:52:47">]
1.9.3-p327 :041 > i.comments
 => [#<Comment id: 7, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:52:47", updated_at: "2013-03-05 12:52:47">]
1.9.3-p327 :042 > i.comments << Comment.new(user_id: User.last.id, body: "item comment")
  User Load (0.8ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
   (0.1ms)  begin transaction
  SQL (0.7ms)  INSERT INTO "comments" ("body", "commentable_id", "commentable_type", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?)  [["body", "item comment"], ["commentable_id", 19], ["commentable_type", "Item"], ["created_at", Tue, 05 Mar 2013 12:53:31 UTC +00:00], ["updated_at", Tue, 05 Mar 2013 12:53:31 UTC +00:00], ["user_id", 2]]
   (30.6ms)  commit transaction
 => [#<Comment id: 7, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:52:47", updated_at: "2013-03-05 12:52:47">, #<Comment id: 8, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:53:31", updated_at: "2013-03-05 12:53:31">]
1.9.3-p327 :043 > i.comments
 => [#<Comment id: 7, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:52:47", updated_at: "2013-03-05 12:52:47">, #<Comment id: 8, body: "item comment", user_id: 2, commentable_id: 19, commentable_type: "Item", created_at: "2013-03-05 12:53:31", updated_at: "2013-03-05 12:53:31">]
1.9.3-p327 :046 >   bp = Blogpost.create
   (0.1ms)  begin transaction
  SQL (1.6ms)  INSERT INTO "blogposts" ("body", "created_at", "title", "updated_at") VALUES (?, ?, ?, ?)  [["body", nil], ["created_at", Tue, 05 Mar 2013 12:54:09 UTC +00:00], ["title", nil], ["updated_at", Tue, 05 Mar 2013 12:54:09 UTC +00:00]]
   (49.3ms)  commit transaction
 => #<Blogpost id: 2, body: nil, title: nil, created_at: "2013-03-05 12:54:09", updated_at: "2013-03-05 12:54:09">
1.9.3-p327 :047 > bp.comments << Comment.new(user_id: u.id, body: "blog comment")
   (2.7ms)  begin transaction
  SQL (1.1ms)  INSERT INTO "comments" ("body", "commentable_id", "commentable_type", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?)  [["body", "blog comment"], ["commentable_id", 2], ["commentable_type", "Blogpost"], ["created_at", Tue, 05 Mar 2013 12:54:42 UTC +00:00], ["updated_at", Tue, 05 Mar 2013 12:54:42 UTC +00:00], ["user_id", 2]]
   (22.2ms)  commit transaction
  Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = 2 AND "comments"."commentable_type" = 'Blogpost'
 => [#<Comment id: 9, body: "blog comment", user_id: 2, commentable_id: 2, commentable_type: "Blogpost", created_at: "2013-03-05 12:54:42", updated_at: "2013-03-05 12:54:42">]
1.9.3-p327 :048 > bp.comments
 => [#<Comment id: 9, body: "blog comment", user_id: 2, commentable_id: 2, commentable_type: "Blogpost", created_at: "2013-03-05 12:54:42", updated_at: "2013-03-05 12:54:42">]

В этом примере мы
  1. Находим товар с id 19 i = Item.find(19)
  2. Находим последнего пользователя u = User.last
  3. Проверяем есть ли комментарии к товару i.comments
  4. Добавляем комментарий i.comments << Comment.new(user_id: u.id, body: "item comment") При этом commentable_type: "Item" у нас проставляется автоматически, commentable_id: 19 тоже проставляется автоматически id товара к которому мы делаем комментарий
  5. Создаем новую запись в блоге bp = Blogpost.create
  6. Добавляем комментарий в блог bp.comments << Comment.new(user_id: u.id, body: "blog comment")
  7. Проверяем наличие комментария bp.comments




Комментариев нет:

Отправить комментарий