Я все еще изучаю Rails и делаю игру-симулятор Google Adwords для обучения. Внутри игры (я могу объяснить только связанную часть этого вопроса) у меня есть три модели: Adgroup (в моем коде называется KeywordAdgroup), Keyword, AdgroupKeyword, а также Модель игры, в которой есть game_id.
Взаимосвязь трех моделей представляет собой ассоциацию has_many through:
, где Adgroup имеет много ключевых слов через AdgroupKeyword, а Keyword имеет много Adgroups через AdgroupKeyword.
Теперь я хочу принять логику, согласно которой каждое ключевое слово можно добавить только в одну группу объявлений конкретной игры. Поэтому я добавил в модель соединения дополнительный атрибут game_id
— AdgroupKeyword, и внедрил в эту модель validates_uniqueness_of :keyword_id, scope: :game_id
.
Однако я обнаружил, что с помощью аналогичного кода я могу проверить уникальность в Create с помощью метода .save
, но не могу проверить уникальность в Update с помощью метода .update(params)
.
Основная проблема заключается в том, что с похожим кодом в create
и update
можно создать save
game_id
в модели присоединения (AdgroupKeyword), где update(params)
не сохранил game_id
в модели присоединения, что в консоли я могу посмотрите, что 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>
Но метод сохранения вставил game_id, который не равен нулю при вставке с использованием метода сохранения. Что-то типа
#<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 (модель группы объявлений)
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 и использую простую форму для создания и обновления группы объявлений.
Я знаю, что это немного грязно, извините за это и спасибо, что прочитали мои слова. Цените любые предложения. Уже потратил несколько часов, чтобы исправить это, но действительно безнадежно после множества разных методов. Думал, что это какая-то концептуальная проблема, которую я не понял.
Обновленная информация
При проверке консоли в методе «Создать» будет:
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]]