Сохранение ассоциации rails has_many с использованием нескольких ключей

У меня есть следующие модели:

class Product < ActiveRecord::Base
  has_many :product_recommendation_sets, :dependent => :destroy
  has_many :recommendation_sets, :through => :product_recommendation_sets
end

class RecommendationSet < ActiveRecord::Base
  has_many :product_recommendation_sets, :dependent => :destroy
  has_many :products, :through => :product_recommendation_sets

  has_many :recommendations 
end

class Recommendation < ActiveRecord::Base
   belongs_to :recommendation_set
end

И я добавляю recommendations recommendations_set вот так:

p = Product.find_by_wmt_id(product) || Product.create( ItemData.get_product_data(product) )     
recommendation =  find_by_rec_id(rec_id) || create( ItemData.get_product_data(rec_id) )        
                rec_set =  RecommendationSet.find_or_create_by_rating_set_id_and_model_version_and_product_id(rating_set.id, model_version, p.id)
                sec_set.update_attributes(
                :rating_set_id => rating_set.id,
                :product_id    => p.id,
                :model_version => model_version,
                :notes => note
                )

                sec_set.recommendations << recommendation
                sec_set.save

prs = ProductRecommendationSet.find_or_create_by_recommendation_set_id_and_rating_set_id_and_product_id(rec_set .id, rating_set.id, p.id,)
            prs.update_attributes(
            :recommendation_set_id => rec_set.id, 
            :rating_set_id => rating_set.id,
            :product_id => p.id
            )

Это работает, как и ожидалось, однако моя проблема в том, что у меня есть несколько recommendation_sets, которые принадлежат нескольким products, и каждый из recommendation_sets может иметь один и тот же recommendation. При сохранении каждого recommendation в recommendation_set, как я сейчас делаю, если два recommendation_sets имеют одинаковые recommendation, только один из наборов добавит это recommendation. Можно ли как-то сохранить каждое recommendation в несколько recommendation_sets с использованием вторичного идентификатора, например, сохранить по recommendation_id_and_product_id, или мне нужно изменить эту связь на has_many :through?


person Yogzzz    schedule 01.10.2013    source источник
comment
Кстати, для первой строки кода, если вы хотите немного упростить ее, вы можете использовать first_or_create метод. Итак, вы должны сделать что-то вроде этого: Product.where(:wmt_id=>product).first_or_create(ItemData.get_product_data(product). Это также будет работать для строки ProductRecommendationSet ниже; вместо того, чтобы использовать этот длинный find_or_create_by_foo_and_bar_and_baz_and...., вы можете поместить все это в .where и вызвать first_or_create   -  person Paul Richter    schedule 01.10.2013
comment
Кроме того, у вас есть дополнительная запятая в конце строки создания ProductRecommendationSet внутри круглых скобок. Кроме того, 2-я строка в блоке создания, у вас есть find_by_rec_id и create сами по себе; какие модели создаются на этой линии? Наконец, 4-я строка в том же блоке, у вас есть переменная с именем sec_set, но я нигде ее не вижу. Это опечатка или переменная определена где-то еще?   -  person Paul Richter    schedule 01.10.2013
comment
И, наконец, не могли бы вы уточнить, верна ли моя интерпретация вашего вопроса: у меня есть 2 набора рекомендаций (RS1 и RS2), оба они указывают на одну и ту же рекомендацию (R). Вы говорите, что, учитывая приведенный выше код, если вы попытаетесь сохранить эти два набора рекомендаций, будет сохранен только один из них (имеется в виду, что RS1 сохраняется, а RS2 нет)?   -  person Paul Richter    schedule 01.10.2013
comment
Спасибо за предложения! Уточнение: у меня есть два набора рекомендаций RS1 и RS2 и несколько рекомендаций, которые им принадлежат, R1..Rn. Как я могу сохранить R1 в RS1, а также сохранить R1 в RS2. Теперь происходит то, что R1 сохраняется в RS2, но не в RS1, потому что R1 может хранить только идентификатор RS2 (только один столбец идентификатора ссылки в моей таблице рекомендаций). Я думаю, что мне, возможно, придется использовать сквозную связь has_many, чтобы я мог создать ассоциацию, используя более одного идентификатора набора рекомендаций.   -  person Yogzzz    schedule 01.10.2013
comment
Окей, кажется, я понял. Я собираюсь опубликовать ответ; подскажите правильно ли я понял.   -  person Paul Richter    schedule 02.10.2013


Ответы (1)


Основываясь на вашем разъяснении, я думаю, что у вас в основном есть отношения «многие ко многим» между RecommendationSet и Recommendation. В настоящее время у вас есть один ко многим.

Есть несколько вариантов:

  1. Используйте метод has_and_belongs_to_many в обеих моделях для описания отношений;
  2. Вручную создайте модель соединения, а затем присвойте RecommendationSet и Recommendation has_many этой модели соединения (с двумя соответствующими строками belongs_to в модели соединения, указывающими на две другие модели);
  3. Стиль has_many ... :through, как вы упомянули

Обратите внимание, что для первых двух вариантов требуется таблица соединений.

Если вам требуется дополнительная информация о таблице/модели соединений, я склоняюсь ко второму варианту. В противном случае либо первое, либо третье вполне допустимы.

Райан Бейтс из RailsCasts сделал об этом эпизод здесь: http://railscasts.com/episodes/47-two-many-to-many

И еще немного информации из документации Rails: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Many-to-many

Короче говоря, если вам не нужна дополнительная информация о соединении, я думаю, что ваше представление о has_many ... :through прекрасно подходит.

Дайте мне знать, поможет ли это

person Paul Richter    schedule 02.10.2013