Rails ActiveRecord:三个表 has_many 通过:关联
Posted
技术标签:
【中文标题】Rails ActiveRecord:三个表 has_many 通过:关联【英文标题】:Rails ActiveRecord: Three Table has_many through: associations 【发布时间】:2014-09-23 00:42:32 【问题描述】:我正在尝试构建一个表格来处理某个活动已设置为具有以下模型关联的位置和类别:
class Campaign < ActiveRecord::Base
has_many :campaign_category_metro_bids, dependent: :destroy
has_many :metros, through: :campaign_category_metro_bids
has_many :categories, through: :campaign_category_metro_bids
end
class Metro < ActiveRecord::Base
has_many :campaign_category_metro_bids
has_many :campaigns, through: :campaign_category_metro_bids
has_many :categories, through: :campaign_category_metro_bids
end
class Category < ActiveRecord::Base
has_many :campaign_category_metro_bids
has_many :campaigns, through: :campaign_category_metro_bids
has_many :metros, through: :campaign_category_metro_bids
end
class CampaignCategoryMetroBid < ActiveRecord::Base
belongs_to :campaign
belongs_to :category
belongs_to :metro
end
当尝试创建一个活动以选择两个不同的城市和类别时,其中一个参数的 id 的结果为 NULL:
广告系列创建代码:
def new
if signed_in?
# create new campaign
@user = User.find(params[:id])
@campaign = @user.campaigns.new
else
redirect_to signin_path
end
end
def create
@campaign = User.find(params["campaign"]["user_id"]).campaigns.build(campaign_params)
if @campaign.save
flash[:success] = "Campaign created!"
redirect_to current_user
else
render 'new'
end
end
更新 创建活动的视图对 Category 和 Metro 使用两个单独的 collection_select:
<%= f.collection_select :category_ids, Category.all, :id, :display_category, , multiple: true %>
和
<%= f.collection_select :metro_ids, Metro.all, :id, :full_name, , multiple: true %>
campaigns_params:
def campaign_params
params.require(:campaign).permit(:name, :campaign_category_metro_bid_id,
:metro_ids => [], :category_ids => [])
end
有没有更好的方法来允许创建 3 表关系,因为我正在尝试?
或在选择时链接Category
和Metro
模型的方法,以便在创建活动时生成的表格如下所示:
【问题讨论】:
您可以从控制器添加您的广告系列创建代码吗? @Eric 您还需要其他信息吗? 是的,你的campaign_params方法:) 好的,我补充了。有没有办法链接Metros
和Category
的选择所以不会出现NULL?
我会考虑创建两个关系表并分别填充它们
【参考方案1】:
如果您想确保跨多个表的数据一致性,我将从验证开始。例如:
class CampaignCategoryMetroBid < ActiveRecord::Base
belongs_to :campaign
belongs_to :category
belongs_to :metro
validates :campaign, presence: true
validates :category, presence: true
validates :metro, presence: true
end
如果您需要,您可能还想将此约束添加到您的数据库中(请参阅迁移指南)。这样,即使是 db cli,也没有人能够打破一致性。现在,每次您的代码尝试创建一个没有外键的 CampaignCategoryMetroBid 实例时,ActiveRecord 都会大喊大叫,这会限制您的其余代码“行为”。
如果您真的只想注入一些默认外键(或以其他方式调整表单数据),您可以在控制器操作中预处理表单数据时执行此操作。例如:
class CampaignsController < ActionController::Base
def create
# Possibly refactor to a before_action
if params[:campaign] && params[:capmaign][:metro_ids] && params[:capmaign][:metro_ids].empty?
params[:campaign][:metro_ids] = [DEFAULT_CAMPAIGN_ID]
end
# Do the rest
end
end
我希望这有助于大致确定方向:-)
【讨论】:
这是否有助于防止此处出现的情况:i.stack.imgur.com/u4TyA.png 我希望将Metros
和Category
的排列选为行中,而不是空值在图像中看到,即。对于category_id
下id 为9,10 的行,它应该列为1
和2
,而不是NULL
我不希望有任何默认的外键,但允许像我演示的那样选择。我需要添加什么?
是的,首先,良好的验证将确保无论您的代码库的其余部分如何处理,这种情况都不会再次发生。这会让你保持一致性。
然后下一步是在您的视图中创建一个下拉菜单(选择框)。用户只需选择一个值(如果您想确保始终选择某些内容,您可能应该禁用空白值)并且该值将映射到将在他提交表单时在参数中发送的 id(外键) .在这里,我会向您指出 Rails 指南,因为他们很好地解释了这一点 - guides.rubyonrails.org/…
是的,我已经在我更新的帖子中看到了collection_select
设置。如何将 Category 和 Metro 两者链接在一起,以便它们填充表格,就像我演示的那样以上是关于Rails ActiveRecord:三个表 has_many 通过:关联的主要内容,如果未能解决你的问题,请参考以下文章
如何编写迁移以重命名 Rails 中的 ActiveRecord 模型及其表?
使用 ActiveRecord 语法从 Rails 中的连接表中选择或按列排序
Rails ActiveRecord_Associations_CollectionProxy 与单表继承