has_many: из-за отношения с одной полиморфной и подклассовой нога ведет себя плохо - PullRequest
0 голосов
/ 16 января 2012

У меня небольшая проблема со следующими моделями (на Rails 3.2rc1). Владение - это отображение Проектов и Блогов Пользователям (Владельцам), и существуют различные типы Блогов, которые по-разному обрабатывают Владение.

class User < ActiveRecord::Base
  has_many :ownerships, dependent: :destroy
  has_many :projects, through: :ownerships, source: :ownable, :source_type => 'Project'
  has_many :site_blogs, through: :ownerships, source: :ownable, :source_type => 'SiteBlog'
end

class Ownership < ActiveRecord::Base
  belongs_to :ownable, polymorphic: true
  belongs_to :owner, :class_name => 'User', foreign_key: 'user_id'
end

class Project < ActiveRecord::Base
  has_many :owners, through: :ownerships, as: :ownable
  has_many :ownerships, as: :ownable, dependent: :destroy
end

class Blog < ActiveRecord::Base
end  

class SiteBlog < Blog
  has_many :owners, through: :ownerships, as: :ownable
  has_many :ownerships, as: :ownable, dependent: :destroy
end

class ProjectBlog < Blog
  belongs_to :project
end

Пока все работает нормально, но SiteBlog#owners плохо себя ведет:

SiteBlog.first.owners
  SiteBlog Load (0.8ms)  SELECT "blogs".* FROM "blogs" WHERE "blogs"."type" IN ('SiteBlog') LIMIT 1
  User Load (1.4ms)  SELECT "users".* FROM "users" INNER JOIN "ownerships" ON "users"."id" = "ownerships"."user_id" WHERE "ownerships"."ownable_id" = 231145885 AND "ownerships"."ownable_type" = 'Blog'
=> []

Проблема в самом конце сгенерированного SELECT: "ownable_type" = 'Blog'. Чтобы это работало, должно быть "ownable_type" = 'SiteBlog', однако я не понимаю, как научить AREL делать это.

Есть идеи?

1 Ответ

0 голосов
/ 18 января 2012

Я создал небольшое приложение для рельсов на основе вашего примера. И это отлично работает.

User.create
SiteBlog.create
SiteBlog.first.owners << User.first

Это создает запись о владельце

#<Ownership id: 5, ownable_id: 5, ownable_type: "Blog", user_id: 5, created_at: 2012-01-17 20:14:01", updated_at: "2012-01-17 20:14:01">

Как вы видите, ownable_type - это "Blog", а не "SiteBlog". Тогда:

SiteBlog.first.owners
SiteBlog Load (0.3ms)  SELECT "blogs".* FROM "blogs" WHERE "blogs"."type" IN ('SiteBlog') LIMIT 1
User Load (0.3ms)  SELECT "users".* FROM "users" INNER JOIN "ownerships" ON "users"."id" = "ownerships"."user_id" WHERE "ownerships"."ownable_id" = 5 AND "ownerships"."ownable_type" = 'Blog'
=> [#<User id: 5, created_at: "2012-01-17 19:44:45", updated_at: "2012-01-17 19:44:45">]

Итак - запрос работает.

А вот и основная часть. Посмотрите на activerecord / lib / activerecord / association / association.rb:

def creation_attributes
  attributes = {}

  if reflection.macro.in?([:has_one, :has_many]) && !options[:through]
    attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]

    if reflection.options[:as]
      attributes[reflection.type] = owner.class.base_class.name
    end
  end

  attributes
end

В частности, эта строка сообщает, что Rails должен писать имя базового класса - это Blog, а не SiteBlog:

attributes[reflection.type] = owner.class.base_class.name

Итак, похоже, все в порядке с вашим примером и поведением Rails.

...