我有这个应用,其中模型User
可以有多个“频道”。应用程序的渠道部分必须能够轻松扩展,每个部分都有自己的模型。
我开始创建一个Channel
模型,其belongs_to
User
关系与User
has_many
Channel
相反。
我在考虑使用与此类似的API:
user = User.create(name: 'John')
user.channels.create(name: 'google', account_id: '1234') # should create a GoogleChannel::Google Model
user.channels.create(name: 'facebook', account_name: 'qwerty') # should create a FacebookChannel::Facebook Model
我正在玩Channel
模型,每个频道模型都有一个专用模型,用于与该模型has_one
关系的每个频道(google,facebook等)。< / p>
更新
我正在使用 mongoid 和rails
答案 0 :(得分:1)
我不确定这是否有效。它使用STI。
第一种方法:单表继承
class User << ApplicationRecord
has_many :channels
delegate :google_channels, :facebook_channels, :twitter_channels, to: :channels
end
class Channel << ApplicationRecord
belongs_to :user
self.inheritance_column = :brand
scope :google_channels, -> { where(brand: 'Google') }
scope :facebook_channels, -> { where(brand: 'Facebook') }
scope :twitter_channels, -> { where(brand: 'Twitter') }
def self.brands
%w(Google Facebook Twitter)
end
end
class GoogleChannel << Channel; end
class FacebookChannel << Channel; end
class TwitterChannel << Channel; end
我认为你可以:
current_user.channels << GoogleChannel.new(name: "First Google Channel")
current_user.channels << Facebook.new(name: "Facebook")
current_user.channels << Twitter.new(name: "Tweety")
current_user.channels << GoogleChannel.new(name: "Second Google Channel")
googs = current_user.google_channels
all = current_user.channels
# etc.
所有频道共享同一张桌子。如果您需要为每个不同的品牌提供不同的属性,这将不是最佳选择。
第二种方法:多态模型
如果每个型号(品牌)需要不同的表格,您可以使用多态方法(未经测试):
class User << ApplicationRecord
has_many :channels
has_many :google_channels, through: :channels, source: :branded_channel, source_type: 'GoogleChannel'
has_many :facebook_channels, through: :channels, source: :branded_channel, source_type: 'FacebookChannel'
end
class Channel << ApplicationRecord
belongs_to :user
belongs_to :branded_channel, polymorphic: true
end
#This channel has its own table, and can have more attributes than Channel
class GoogleChannel << ApplicationRecord
has_one :channel, as: :branded_channel
end
#This channel has its own table, and can have more attributes than Channel
class FacebookChannel << ApplicationRecord
has_one :channel, as: :branded_channel
end
goog = GoogleChannel.create(all_google_channel_params)
face = GoogleChannel.create(all_facebook_channel_params)
current_user.channels << Channel.new(branded_channel: goog)
current_user.channels << Channel.new(branded_channel: face)
答案 1 :(得分:1)
我假设你想创建一个User
有很多频道的STI,所以在Rails 5你可以试试这个:
class User < ApplicationRecord
has_many :user_channels
has_many :channels, through: :user_channels
has_many :facebook_channels, class_name: 'FacebookChannel', through: :user_channels
has_many :google_channels, class_name: 'GoogleChannel', through: :user_channels
end
class UserChannel < ApplicationRecord
# user_id
# channel_id
belongs_to :user
belongs_to :channel
belongs_to :facebook_channel, class_name: 'FacebookChannel', foreign_key: :channel_id, optional: true
belongs_to :google_channel, class_name: 'GoogleChannel', foreign_key: :channel_id, optional: true
end
class Channel < ApplicationRecord
# You need to have "type" column to be created for storing different chanels
has_many :user_channels
has_many :users, through: :user_channels
end
class FacebookChannel < Channel
has_many :user_channels
has_many :users, through: :user_channels
end
class GoogleChannel < Channel
has_many :user_channels
has_many :users, through: :user_channels
end
现在您可以执行current_user.facebook_channels.create(name: "My Facebook Channel")
并使用FacebookChannel
获取所有current_user.facebook_channels
基本上它与STI额外功能的常规has_many through
关系一样 - 您将子模型名称存储在type
模型的Channel
列中。
<强>更新强>
对不起,我不知道我的建议不适用于MongoDB。也许您只需在channel_type
表格中创建channels
列,即可建立简单的channel belongs_to user
关系,然后执行以下操作:
current_user.channels.create(name: "My Channel Name", channel_type: "facebook")
current_user.channels.where(channel_type: "facebook")
您可以简单地current_user.channels
为用户提供所有渠道,然后如果您需要,您可以根据channel_type
值对每条记录执行所需操作。
您甚至可以在Channel model中创建一些范围:
class Channel < ApplicationRecord
scope :facebook_channels, -> { where(channel_type: "facebook") }
end
然后你可以做你想要的current_user.channels.facebook_channels
channel_type
列可以是字符串或整数。
此外,如果您创建visit
列(例如&#34;布尔&#34;),您可以执行current_user.channels.where(visit: true)
或创建scope :visit_true, -> { where(visit: true) }
并执行current_user.channels.visit_true
之类的操作
你说什么?