Rails 3.2.13 — Удалить запись из вложенных атрибутов

У меня есть приложение Ruby on Rails 3.2.13, в котором есть инструкция collection_select. Оператор collection_select находится в операторе fields_for, где я собираю выбранные идентификаторы из collection_select и использую их для заполнения другой таблицы. Проблема, с которой я сталкиваюсь, заключается в том, что оператор collection_select добавляет запись с нулевым идентификатором в массив, в котором хранится коллекция выбранных идентификаторов.

Вот мой код на мой взгляд:

<%= f.fields_for :media_topics do |media_topic| %>
  <%= media_topic.label :topic, "Topics" %><%= media_topic.collection_select(:topic_id, Topic.order("name_en"), :id, :name_en, {}, {multiple: true}) %>
<% end %>

Вот пример того, как выглядит массив после выбора двух опций:

"media_topics_attributes"=>{"0"=>{"topic_id"=>["", "2", "47"], "id"=>"1895"}}

Через другого члена Stack Overflow я узнал, что пустая запись в collection_select является скрытым значением, которое автоматически включается. В Rails 3 нет возможности не включать это поле. Однако, согласно ссылке, приведенной в ответе на мой предыдущий вопрос the-first-position-of-my-ar">Rails 3.2 - collection_select Добавление нулевой записи в первую позицию моего массива будет способ исключить это скрытое значение в Rails 4.

Я пропускал это значение и добавлял строки MediaTopic вручную, прежде чем решил использовать accepts_nested_attributes_for в первый раз. Я хочу сделать мой код контроллера чище, чем сейчас. Проблема, с которой я сталкиваюсь, заключается в том, чтобы выяснить, как пропустить эту пустую запись. Я прочитал API и многие другие сообщения о том, как я должен пропустить это значение, но ни один из них не работает.

Вот код, который у меня есть для вложенных атрибутов media_topics в моей модели MediaLibrary.

has_many :media_topics, dependent: :destroy
accepts_nested_attributes_for :media_topics, allow_destroy: true, reject_if: proc { |attributes| attributes['id'].blank? }

Модель темы в collection_select имеет поле :id, которое будет обновлять поле :topic_id в модели MediaTopic. Другое поле в MediaTopic — :media_library_id. Я попробовал поля id и topic_id в команде accepts_nested_attributes_for, но когда я делаю update_attributes для основной модели, я получаю сообщение об ошибке, говорящее, что тема не может быть пустой. Я уверен, что ошибка возникает из-за попытки создать строку MediaTopic для первой пустой записи в массиве.

Я исследовал это в течение нескольких дней, но ничего из того, что я пробовал, не работает. Я проверил API, APIDock и другие источники безрезультатно. Я хочу удалить пустую запись из media_topics_attributes до того, как сделаю update_attributes. Наверное, я не понимаю, как писать код. Я видел это в API в качестве примера, но я понятия не имею, куда это должно идти или как я должен кодировать это, чтобы избавиться от пустого значения.

params = { member: {
  posts_attributes: [{ id: '2', _destroy: '1' }]
}}

Любая помощь будет оценена по достоинству.

ОБНОВЛЕНИЕ 10 августа 2013 г., 22:46 CDT

В моем контроллере у меня есть следующее предложение when в моем операторе case после завершения проверки всех ошибок.

when @media_library.update_attributes(params[:media_library])

ОБНОВЛЕНИЕ 12.08.2013, 8:20 CDT

В модели MediaLibrary я изменил свой accepts_nested_attributes_for на следующий.

accepts_nested_attributes_for :media_topics, allow_destroy: true

ОБНОВЛЕНИЕ 12 августа 2013 г., 10:50 CDT

Вот как выглядит хеш в моей отладке:

media_topics_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
    '0': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      topic_id:
      - '2'
      - '47'
      id: '1896'

Однако я все еще получаю сообщение об ошибке Тема тем СМИ не может быть пустой. Я буду продолжать искать.

ОБНОВЛЕНИЕ 12 августа 2013 г., 12:15 CDT

Тема — это модель со списком имен (:id, :name)

MediaLibrary — это список строк, которые я хочу выбрать по Topic.name.

MediaTopic — это список строк, которые связывают Topic с MediaLibrary.

MediaLibrary has_many :media_topics, зависимый: :destroy

Тема has_many :media_topics

MediaTopic принадлежит_к :media_library принадлежит_к :теме

Экран, над которым я работаю, будет вносить изменения в MediaLibrary и обновлять MediaTopic в зависимости от оператора collection_select, в котором перечислены имена тем.


person Pamela Cook - LightBe Corp    schedule 10.08.2013    source источник


Ответы (2)


в модели MediaLibrary

alias_method :underlying_media_topics_attributes=, :media_topics_attributes=

def media_topics_attributes=(hash_of_hashes)
  hash_of_hashes.each { |key, hash| hash[:topic_id].reject!(&:blank?) }
  self.underlying_media_topics_attributes=(hash_of_hashes)
end
person bgates    schedule 11.08.2013
comment
bgates, большое спасибо за ваш вклад. Я добавил в свой вопрос, как я обновляю MediaLibrary, которая одновременно обновляет атрибуты media_topics_attributes с допустимыми значениями в хеше. Я добавил метод, который вы опубликовали, в модель MediaTopic. Однако я не уверен, где я мог бы получить доступ к этому методу. Я думаю, что мне следует получить к нему доступ в моей модели MediaLibrary, но я не уверен, как передать ему атрибуты media_topic_attributes. Могу ли я заменить PROC в моем предложении :reject_if этим методом? Недавно я прошел курс Ruby, но иногда этот тип записи был мне непонятен :) - person Pamela Cook - LightBe Corp; 11.08.2013
comment
Моя ошибка, этот метод идет в модели MediaLibrary. Я отредактировал свой первоначальный ответ. - person bgates; 12.08.2013
comment
Я переместил метод в модель MediaLibrary. Я разместил обновление о том, как я изменил модель. Я получил ошибку в моем операторе update_attributes в моем контроллере. Завершено 500 Internal Server Error за 6 мс NoMethodError (super: нет метода суперкласса media_topics_attributes=' for #<MediaLibrary:0x007f8bd63177e8>): app/models/media_library.rb:73:in media_topics_attributes=' app/controllers/media_libraries_controller.rb:135:in `update' Если я закомментирую super, обновлений не произойдет. У меня нет примера в моих примечаниях к классу Ruby. Как я могу сослаться на этот метод и где (модель или контроллер)?Спасибо! - person Pamela Cook - LightBe Corp; 12.08.2013
comment
Я смущен. Не может быть вызовом super, потому что ActiveRecord не знает, что такое media_topics_attributes=. Я отредактировал свой ответ; этот я тестировал в консоли с моделью, которая принимает вложенный атрибут, и alias_method, кажется, делает то, что мы хотим. - person bgates; 12.08.2013
comment
Не смущайтесь. Я многому учусь у тебя. Код из вашего обновленного ответа удаляет пустую запись. Проверьте мое обновление. Однако я все еще получаю сообщение об ошибке Тема для СМИ не может быть пустой. У меня есть проверки :topic_id, присутствие: true в модели MediaTopic. Если я удалю его, будет создана строка MediaTopic с пустым идентификатором, что вызовет проблемы с моим collection_select, ищущим строку темы с пустым идентификатором. Похоже, что MediaTopic проверяется перед MediaLibrary. Можно ли перенести проверку :topic_id в MediaLibrary, где она будет выполнять проверку после удаления пустого идентификатора из хэша? - person Pamela Cook - LightBe Corp; 12.08.2013
comment
OK, MediaLibrary has_many :media_topics и MediaTopic...has_many :topics? Или не МедиаТопик belong_to :topic? - person bgates; 12.08.2013
comment
Если MediaTopic belongs_to :topic, вы не можете присвоить ему два разных значения topic_id, как это делает ваша форма прямо сейчас. Попробуй в консоли - найди MediaTopic, затем задай для его theme_id значение [2,47] и посмотри, что получится. Я получаю предупреждение о том, чтобы переместить это в чат, но я ухожу на некоторое время - задайте другой вопрос, если хотите, потому что пустой элемент массива больше не проблема, с которой вы имеете дело, это тот факт, что вы иметь массив в первую очередь. - person bgates; 12.08.2013
comment
давайте продолжим это обсуждение в чате - person Pamela Cook - LightBe Corp; 12.08.2013
comment
Недавно я переписал свое приложение Rails, используя Rails 4.0.0. В первом наборе скобок я добавил include_hidden: false, и нулевая запись не появляется в массиве. - person Pamela Cook - LightBe Corp; 11.11.2013

По словам @vinodadhikary, пустая запись в массиве работает, как и ожидалось, в Rails 3. Недавно я переписал это приложение в Rails 4. Я полностью переписал логику, сначала используя has_many, чтобы связать все мои таблицы. Я также заменил логику fields_for, просто используя оператор collection_select. Я добавил include_hidden = false в первый {}, и нулевая запись не появляется в массиве. Я задал аналогичный вопрос несколько дней назад, и после долгих поисков я нашел решение. Подробности по ссылке ниже.

Rails 4 – Использование collection_select для получения массива идентификаторов для промежуточной таблицы с вложенными атрибутами

person Pamela Cook - LightBe Corp    schedule 13.11.2013