【问题标题】:Having trouble in updating join model extra attributes in has_many through association - Rails通过关联更新 has_many 中的连接模型额外属性时遇到问题 - Rails
【发布时间】:2017-04-18 21:52:09
【问题描述】:

我仍然是 Rails 的学习者,并且正在制作一个 Google Adwords 的模拟游戏用于培训使用。在游戏内部(我可能只解释这个问题的相关部分),我有三个模型,Adgroup(在我的代码中称为KeywordAdgroup),Keyword,AdgroupKeyword,还有一个包含 game_id 的游戏模型。

三个模型的关系是一个has_many through:关联,其中Adgroup通过AdgroupKeyword有很多Keyword,Keyword通过AdgroupKeyword有很多Adgroup。

现在,我想采用一个逻辑,即每个关键字只能添加到特定游戏的单个广告组中。所以我在join模型中添加了一个额外的属性game_id——AdgroupKeyword,并在这个模型中采用了validates_uniqueness_of :keyword_id, scope: :game_id

但是,我发现使用类似的代码,我可以使用 .save 方法验证 Create 中的唯一性,但我无法使用 .update(params) 方法验证 Update 中的唯一性。

主要的问题是,createupdate 中的类似代码,创建一个可以save game_id 到连接模型(AdgroupKeyword),其中update(params) 没有保存game_id 到 join 模型,在控制台中,我可以看到 update 没有将 game_id 插入记录。

会变成game_id: nil:

#<AdgroupKeyword id: 180, keyword_id: 9, created_at: "2016-12-04 11:12:00", updated_at: "2016-12-04 11:12:00", keyword_adgroup_id: 77, game_id: nil>

但是save方法确实插入了game_id,使用save方法插入时game_id不是nil。 类似的东西

#<AdgroupKeyword id: 174, keyword_id: 10, created_at: "2016-12-04 10:23:50", updated_at: "2016-12-04 10:23:50", keyword_adgroup_id: 77, game_id: 3>

以下是我的代码:

keyword_adgroup.rb(Adgroup的模型)

class KeywordAdgroup < ApplicationRecord
  belongs_to :keyword_campaign

  has_many :adgroup_keywords, inverse_of: :keyword_adgroup, dependent: :destroy
  has_many :keywords, through: :adgroup_keywords, source: :keyword
  accepts_nested_attributes_for :adgroup_keywords, allow_destroy: true

  ...

  accepts_nested_attributes_for :keywords

  ...

  ...
end

keyword.rb

class Keyword < ApplicationRecord
  ...

  ...

  has_many :keyword_adgroups, through: :adgroup_keywords
  has_many :adgroup_keywords

  ...
end

adgroup_keyword.rb(连接模型)

class AdgroupKeyword < ApplicationRecord
  belongs_to :keyword_adgroup
  belongs_to :keyword

  validates_uniqueness_of :keyword_id, scope: :game_id

end

而且主要是在 Adgroup 控制器中建立关系。

adgroups_controller.rb

class Adwords::AdgroupsController < AdwordsController

  def index
    ...
  end

  def new
    @adgroup = KeywordAdgroup.new
  end

  def create
    @campaign = current_user.game.keyword_campaigns.find(params[:keyword_campaign_id])
    @adgroup = @campaign.keyword_adgroups.build(adgroup_params)
    @adgroup.game_id = @campaign.game_id
    @adgroup.adgroup_keywords.each do |join|
      join.game_id = @adgroup.game_id    
    end

    if @adgroup.save
      redirect_to new_adwords_ad_path(keyword_adgroup_id: @adgroup.id)
    else
      render :new
    end
  end

  def edit
    @adgroup = KeywordAdgroup.find(params[:id])
  end

  def update
    @adgroup = KeywordAdgroup.find(params[:id])
    @campaign = @adgroup.keyword_campaign
    @adgroup.game_id = @campaign.game_id
    @joins = @adgroup.adgroup_keywords
    @joins.each do |join|
      join.game_id = @adgroup.game_id  
    end 
    if @adgroup.update(adgroup_params)

      redirect_to adwords_adgroups_path, notice: "Adgroup updated"
    else
      render :edit
    end
  end

  ...

  private
  def adgroup_params
    params.require(:keyword_adgroup).permit(:name, :activate, :bid, keyword_ids: [], adgroup_keywords_attributes: [:game_id])
  end

end

在同一个游戏的任何广告组中选择重复关键字时,在“创建”中,它会回滚;在“更新”中,它只会用game_id: nil更新记录。

仅供参考,我正在使用 Ruby 2.3.0、Rails 5.0.0,并使用 simpleform 来创建和更新广告组。

我知道它有点乱,对此感到抱歉,感谢您阅读我的话。感谢任何建议。已经花了几个小时来修复它,但经过很多不同的方法后真的没有希望了。还以为是一些概念上的问题我还没想通。


更新信息

在检查控制台时,在“创建”方法中,会出现:

  AdgroupKeyword Exists (0.4ms)  SELECT  1 AS one FROM "adgroup_keywords" WHERE "adgroup_keywords"."keyword_id" = ? AND "adgroup_keywords"."game_id" = ? LIMIT ?  [["keyword_id", 14], ["game_id", 3], ["LIMIT", 1]]
  Keyword Exists (0.3ms)  SELECT  1 AS one FROM "keywords" WHERE "keywords"."keyword" = ? AND ("keywords"."id" != ?) LIMIT ?  [["keyword", "Japan local trip"], ["id", 14], ["LIMIT", 1]]
  KeywordAdgroup Exists (0.2ms)  SELECT  1 AS one FROM "keyword_adgroups" WHERE "keyword_adgroups"."name" = ? AND "keyword_adgroups"."keyword_campaign_id" = ? LIMIT ?  [["name", "3"], ["keyword_campaign_id", 36], ["LIMIT", 1]]
  SQL (2.3ms)  INSERT INTO "keyword_adgroups" ("name", "activate", "bid", "created_at", "updated_at", "keyword_campaign_id", "game_id") VALUES (?, ?, ?, ?, ?, ?, ?)  [["name", "3"], ["activate", true], ["bid", #<BigDecimal:7fcaac52c320,'0.1E1',9(18)>], ["created_at", 2016-12-04 13:10:19 UTC], ["updated_at", 2016-12-04 13:10:19 UTC], ["keyword_campaign_id", 36], ["game_id", 3]]
  SQL (0.2ms)  INSERT INTO "adgroup_keywords" ("keyword_id", "created_at", "updated_at", "keyword_adgroup_id", "game_id") VALUES (?, ?, ?, ?, ?)  [["keyword_id", 14], ["created_at", 2016-12-04 13:10:19 UTC], ["updated_at", 2016-12-04 13:10:19 UTC], ["keyword_adgroup_id", 84], ["game_id", 3]]
  AdgroupKeyword Exists (0.3ms)  SELECT  1 AS one FROM "adgroup_keywords" WHERE "adgroup_keywords"."keyword_id" = ? AND ("adgroup_keywords"."id" != ?) AND "adgroup_keywords"."game_id" = ? LIMIT ?  [["keyword_id", 14], ["id", 187], ["game_id", 3], ["LIMIT", 1]]

在“更新”方法中,会变成:

  AdgroupKeyword Exists (0.2ms)  SELECT  1 AS one FROM "adgroup_keywords" WHERE "adgroup_keywords"."keyword_id" = ? AND "adgroup_keywords"."game_id" IS NULL LIMIT ?  [["keyword_id", 17], ["LIMIT", 1]]
  SQL (2.0ms)  INSERT INTO "adgroup_keywords" ("keyword_id", "created_at", "updated_at", "keyword_adgroup_id") VALUES (?, ?, ?, ?)  [["keyword_id", 17], ["created_at", 2016-12-04 13:07:03 UTC], ["updated_at", 2016-12-04 13:07:03 UTC], ["keyword_adgroup_id", 82]]
  AdgroupKeyword Exists (0.2ms)  SELECT  1 AS one FROM "adgroup_keywords" WHERE "adgroup_keywords"."keyword_id" = ? AND ("adgroup_keywords"."id" != ?) AND "adgroup_keywords"."game_id" = ? LIMIT ?  [["keyword_id", 11], ["id", 185], ["game_id", 3], ["LIMIT", 1]]

【问题讨论】:

    标签: ruby-on-rails ruby crud has-many-through jointable


    【解决方案1】:

    您能否尝试#update 调用(在if 块内)运行此块?

    @adgroup.reload
    
    @adgroup.adgroup_keywords.each do |join|
      join.update(:game_id, @adgroup.game_id)
    end
    

    【讨论】:

    • 哦,你是对的,因为在我的“创建”中,第一步需要选择关键字广告系列,因此,传递campaign_id 并创建广告组。但它为什么以及如何影响我的“更新”方法?非常感谢!
    • 我刚刚更新了我的答案——你能检查一下它是否真的通过了game_id 值吗?
    • 谢谢,我已经更新了底部的一些信息。我之前曾尝试将其从允许的参数中删除,但没有运气。几个小时都感到困惑。
    • 谢谢。你能在#update 调用之前打印adgroup_params 吗?
    • 我想过这样的事情:我已经为广告组的每个 adgroup_keyword(join model) 设置了 game_id,但是@adgroup.save 知道将 game_id 保存到数据库中; @adgroup.update(adgroup_params) 不知道将 game_id 保存到数据库中。但是我应该如何解决呢?
    猜你喜欢
    • 2010-09-29
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    相关资源
    最近更新 更多