Rails 请教一个 ActiveRecord 关联关系的方法

as181920 · 2013年06月08日 · 最后由 as181920 回复于 2013年06月09日 · 4487 次阅读

有客户 Customer,每个客户有东西比如 Music,Video,Article 等,model 参考

class Customer < ActiveRecord::Base
end

class Video < ActiveRecord::Base
end
class Music < ActiveRecord::Base
end
class Article < ActiveRecord::Base
end

上面很简单很干净哈,然后要关联每个客户的这些东西,但是不打算修改这些东西的表结构(不行再考虑改结构),通过关联表的方式建立关联关系。

期望的效果是: Customer.find(x).articles # 可查询客户的所有文章 Customer.find(x).articles.create {} # 可直接基于用户新建他的某类东西

直接 sql 还好,但是用 AR 的 has_many+through+polymorphic 等,我没折腾出来,身边就我一个技术没人讨论,只好来这里请教:)

没看明白,你是不是说的是 build http://rubyer.me/blog/262/

#1 楼 @xmonkeycn 这个方法对每一类用户和东西的关系都要一个关联关系表/model,我有很多不同类的客户资料/东西,就要建很多几乎一样的关系表,有点浪费。

给每个表加一个 customer_id 也可以关联,一则对这么多表做修改感觉改动大,笔误的机会多;二则如果某天不想要这个关系了又要动数据库结构,三则如果后面需要这个关系本身要做更多的事情,没法扩展功能,但是关系表本身可以加字段来处理新的逻辑

考虑过加一个关系表,参考

Meixianghaomingzi < ActiveRecord::Base
  belongs_to :customer
  belongs_to :resource_id, :resource_type
end

一头关联用户,一头关联各类资源/东西,没弄成。

http://ruby-china.org/topics/227 用这个关联方法可以查询,新建要两条语句(关系要单独加)。

试试这样:建立一个含有 type 字段的 resource 表,用来进行单表继承。分别派生出 ImageResource,VideoResource 等等用来在 Costomer 中设置 has_many :through 关联。我想应该就满足你的需求了。

Migration:

class CreateResources < ActiveRecord::Migration
  def change
    create_table :resources do |t|
      t.string :type
      t.integer :entity_id
      t.integer :customer_id

      t.timestamps
    end
  end
end

Model:

class Resource < ActiveRecord::Base
  attr_accessible :customer_id, :entity_id, :type
  belongs_to :customer
end

class ImageResource < Resource
  belongs_to :image, foreign_key: 'entity_id'
end

class VideoResource < Resource
  belongs_to :video, foreign_key: 'entity_id'
end

class Customer < ActiveRecord::Base
  attr_accessible :name
  has_many :image_resources
  has_many :video_resources
  has_many :images, through: :image_resources
  has_many :videos, through: :video_resources
end

#6 楼 @xmonkeycn 上面有个代码我手误写错了,guide 这些案例满足不了需求,结合没搞定。

#7 楼 @reyesyang 多谢,这是一个想法我回头考虑下。不过 model 里面没看出来怎么区分 type(哪里给 resource 的 type 赋值)。

#8 楼 @as181920 单表继承中 type 字段的赋值 Rails 会自己处理,算是 Rails 的魔法。具体可参考 http://poshboytl.iteye.com/blog/461623

#6 楼 @xmonkeycn 今天过来重新整齐写上代码,测试居然 ok 了,还是基础的关系加 polymorphic。前面可能我哪里笔误操作错误,也可能用了 resource 这个词跟哪里保留词冲突了。 现在实现代码参考如下

class User < ActiveRecord::Base
  has_many :ownerships
  ItemTypes = ["WeixinUser","KeywordReply","News","Audio","ReplyText","Article","Video","Picture","Activity","Shop"]
  ItemTypes.each do |item_type|
    has_many item_type.underscore.pluralize.to_sym, through: :ownerships, source: "item", source_type: item_type
  end

  def to_s
    self.email
  end
end

class Ownership < ActiveRecord::Base
  attr_accessible :user_id, :item_id, :item_type

  belongs_to :user
  belongs_to :item, polymorphic: true, :primary_key => :id
  validates_presence_of :item_id, :item_type
end

class Audio < ActiveRecord::Base
  has_one :ownership, as: :item, dependent: :destroy
end
需要 登录 后方可回复, 如果你还没有账号请 注册新账号