2014-01-13 126 views
0

我得到了下面的用例:ActiveRecord关联

我有三种类型的UsersAdvertisersPublishersAdministrators。每个用户都有一些共同的属性(如姓名或姓氏),但也有几个独特的关联。广告客户与Ad(verteisement)s和Campaigns有关联。每个人都是自己的另一种模式。

我的问题是我将如何去使用ActiveRecord s?迁移代码的外观如何?

这里是模型类:

用户:

class User < ActiveRecord :: Base 
    require 'pbkdf2' 
    require 'date' 

    has_many :messages 

    attribute :name, :surname, :email, :password_hash, :password_salt 
    attr_accessor :password, :password_confirmation, :type 

    attribute :user_since, :default => lambda{ Date.today.to_s } 

    [...] 
end 

出版商:

class Publisher < User 
    has_many :websites 
end 

广告:

class Advertiser < User 
    has_many :campaigns 
    has_many :ads 
end 

我得到了以下迁移文件来创建User

class AddUser < ActiveRecord::Migration 
    def up 
    create_table :users do |t| 
     t.string :name 
     t.string :surname 
     t.string :email 
     t.string :password_hash 
     t.string :password_salt 
     t.date :user_since 
     t.string :type 
    end 

    create_table :messages do |t| 
     t.belongs_to :user 
     t.string :account_number 
     t.timestamps 
    end 
    end 

    def down   
    drop_table :user 
    end 
end 

如何修改这个文件,以便纳入上述关联?

编辑:更正了使用复数形式的关联。

回答

1

多态关系是解决这个问题的一种方法,而另一种方法是使用单表继承(STI)。每种方法都有其优点和缺点,您的决定可能取决于User的子类别往往会有多不同。他们会有更大的不同,决定会越倾向于多态关系。

使用STI方法:

# a single :users table 
# one table for each of the other (non-user) models 

class User < ActiveRecord::Base 
    has_many :messages 
end 

class Publisher < User 
    has_many :websites 
end 

class Advertiser < User 
    # if :campaign supports multiple user-types (polymorphic) 
    has_many :campaigns, :as => :user 
    # otherwise 
    has_many :campaigns 

    has_many :ads 
end 

class Message < ActiveRecord::Base 
    belongs_to :user 
end 

class Campaign < ActiveRecord::Base 
    # if multiple user-types will have campaigns 
    belongs_to :user  # referential column should be :user_id 
    # otherwise 
    belongs_to :advertiser # referential column should be :advertiser_id 
end 

使用多态的方法:

# there should be no :users table, as User will be an abstract model class 
# instead make a table for each of all the other models 

class User < ActiveRecord::Base 
    self.abstract_class = true 
    has_many :messages, :as => :messageable 
end 

class Publisher < User 
    has_many :websites 
end 

class Advertiser < User 
    has_many :campaigns 
    has_many :ads 
end 

class Message < ActiveRecord::Base 
    belongs_to :messageable, polymorphic: true # referential columns should be :messageable_id and :messageable_type 
end 

class Campaign < ActiveRecord::Base 
    # if multiple user-types will have campaigns 
    belongs_to :user, polymorphic: true # referential columns should be :user_id and :user_type 
    # otherwise 
    belongs_to :advertiser     # referential column should be :advertiser_id 
end 
+0

的类正是我张贴他们的方式。您可以添加一个简短的例子来说明如何通过STI来实现它的工作吗?我开始使用STI是因为我找到了一个似乎符合我需求的教程,但是我在原帖中偶然发现了这个问题。 – Nessuno

+0

澄清的要点,但不要STI模型[共享同一个表的属性](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance)? – zeantsoi

+0

@zeantsoi - 是的,他们共享同一个表的属性,这在这里似乎不成问题。 _associations_是不同的,它们显然是'has_many'关联,这意味着参考列被添加到子模型中。再次,这里不是问题。 – PinnyM