actions-as-taggable-on создает дубликаты строк в базе данных
Я использую действия-как-taggable-on для приложения Rails, и каждый раз, когда я создаю новую фотографию (например), я получаю дублирующиеся строки в таблице "тегов".
Мои классы моделей выглядят примерно так:
class User < ActiveRecord::Base
acts_as_tagger
...
end
а также
class Photo < ActiveRecord::Base
acts_as_taggable_on :tags
...
end
и в действии создания моего photos_controller
def create
@user = current_user
...
@user.tag(@photo, :with => params[:photo][:tag_list], :on => :tags)
...
end
Странно то, что я получаю повторяющиеся строки в таблице "taggings", где в первой строке "tagger_id" и "tagger_ty pe" установлены в NULL, в то время как дублирующаяся строка имеет правильные значения.
мой Gemfile выглядит так
gem 'rails', '3.2.8'
gem 'acts-as-taggable-on', '~> 2.3.1'
Кто-нибудь видел такое поведение раньше? Это проблема конфигурации на моем конце?
Обновление: Глядя на консоль, я ясно вижу две транзакции, которые выполняются, и в первой есть:
SQL (0.6ms) INSERT INTO "taggings" ("context", "created_at", "tag_id",
"taggable_id", "taggable_type", "tagger_id", "tagger_type") VALUES (?, ?, ?, ?, ?, ?, ?)
[["context", "tags"], ["created_at", Thu, 27 Sep 2012 21:49:22 UTC +00:00], ["tag_id",
12], ["taggable_id", 10], ["taggable_type", "Photo"],
["tagger_id", nil], ["tagger_type", nil]]
и ясно, что tagger_id имеет значение null, а также tagger_type.
Вот полный вывод на консоль, я разделил строки, чтобы помочь его прочитать. Вы заметите две отдельные транзакции, и в первой есть вставка со значениями NULL, а в конце второй вы увидите правильную.
Запуск POST "/photo" для 127.0.0.1 в 2012-09-28 07:39:58 +0200 Обработка PhotoController#create в виде HTML-параметров: {"utf8"=>"✓", "authenticity_token"=>"IOmnfDpU7V7vYw3h6RXXzXPsXf/B0fcVihXhb+S8JHU=", "photo"=>{"url"=>"www.another.com/photo.jpg", "title"=>"Another", "tag_list"=>"a_tag", "description"=>"", "private"=>"0"}, "commit"=>"Добавить фотографию"} Перенаправлено на http://www.somedomain.com:3000/users/christiangiacomi
Завершено 302 Найдено за 414 мс (ActiveRecord: 20,5 мс)
Пользовательская нагрузка (0,3 мс) ВЫБРАТЬ "пользователи".* ИЗ "пользователей" ГДЕ "пользователи". "Username" = 'christiangiacomi' LIMIT 1 ActsAsTaggableOn::Tag Load (0,2 мс) ВЫБРАТЬ "теги".* ИЗ "теги" INNER ПРИСОЕДИНЯЙТЕСЬ "taggings" ON "tags". "Id" = "taggings"."Tag_id" ГДЕ "taggings". "Taggable_id" IS NULL AND "taggings"."Taggable_type" = 'Фотография' AND (taggings.context = 'tags 'AND taggings.tagger_id IS NULL)
(0,1 мс) начать транзакцию
SQL (6,2 мс) INSERT INTO "photos" ("made_at", "description", "favourite", "private", "title", "updated_at", "url", "user_id") ЗНАЧЕНИЯ (?,?,?,?,?,?,?,?) [["creat_at", пт, 28 сен 2012 05:39:59 UTC +00:00], ["description", ""], ["favourite", false), ["private", false], ["title", "Another"], ["updated_at", пт, 28 сентября 2012 г. 05:39:59 UTC +00: 00], ["url", "http: / /www.another.com/photo.jpg "], [" user_id ", 1]]
ActsAsTaggableOn:: Tag Load (3.2ms) ВЫБРАТЬ "теги".* FROM "теги" WHERE (lower(name) = 'a_tag') ActsAsTaggableOn::Tag Существует (0,1 мс) SELECT 1 AS one FROM "теги" WHERE "теги "." name "= 'a_tag' LIMIT 1
SQL (0,2 мс) INSERT INTO "tags" ("name") VALUES (?) [["Name", "a_tag"]]
ActsAsTaggableOn:: Tag Load (0.1ms) ВЫБРАТЬ "теги".* FROM "теги" INNER JOIN "теги" ON "теги". "Id" = "теги". "Tag_id" ГДЕ "теги". "Taggable_id" = 13 AND "taggings"."Taggable_type" = 'Фото' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL)
ActsAsTaggableOn:: Tagging существует (0,2 мс) ВЫБЕРИТЕ 1 КАК один из "taggings" WHERE ("taggings"."Tag_id" = 16 AND "taggings"."Taggable_type" = 'Photo' AND "taggings"."Taggable_id" = 13 AND "taggings"."Context" = "теги" AND "taggings". "Tagger_id" IS NULL AND "taggings"."Tagger_ty pe" IS NULL) LIMIT 1
SQL (0,7 мс) INSERT INTO "taggings" ("context", "create_at", "tag_id", "taggable_id", "taggable_type", "tagger_id", "tagger_type") ЗНАЧЕНИЯ (?,?,?,?,?,?,?) [["context", "tags"], ["creation_at", пт, 28 сентября 2012 05:39:59 UTC +00: 00], ["tag_id", 16], ["taggable_id", 13], ["taggable_ty pe", "Photo"], ["tagger_id", nil], ["tagger_ty pe", nil]]
(4.1ms) совершить транзакцию
(0,1 мс) начать транзакцию
ActsAsTaggableOn::Tag Load (0.2ms) ВЫБРАТЬ "теги".* FROM "теги" ГДЕ (нижний (имя) = 'a_tag')
ActsAsTaggableOn:: Загрузка тегов (0,2 мс) ВЫБРАТЬ "теги".* FROM "теги" INNER JOIN "теги" ON "теги". "Id" = "теги". "Tag_id" ГДЕ "теги". "Taggable_id" = 13 AND "taggings"."Taggable_type" = 'Фото' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL)
CACHE (0.0ms) ВЫБЕРИТЕ "теги".* ИЗ "тегов" ГДЕ (нижний (имя) = 'a_tag')
ActsAsTaggableOn:: Загрузка тегов (0,2 мс) ВЫБРАТЬ "теги".* FROM "теги" INNER JOIN "теги" ON "теги". "Id" = "теги". "Tag_id" ГДЕ "теги". "Taggable_id" = 13 AND "taggings"."Taggable_type" = 'Фото' AND (taggings.context = 'tags' AND taggings.tagger_id = 1 AND taggings.tagger_type = 'Пользователь')
ActsAsTaggableOn:: Tagging Exists (0,4ms) ВЫБЕРИТЕ 1 КАК один ИЗ "taggings" WHERE ("taggings"."Tag_id" = 16 AND "taggings"."Taggable_type" = 'Photo' AND "taggings"."Taggable_id" = 13 AND "taggings"."Context" = "теги" AND "taggings". "Tagger_id" = 1 AND "taggings"."Tagger_ty pe" = 'User') LIMIT 1
SQL (0,5 мс) INSERT INTO "taggings" ("context", "creation_at", "tag_id", "taggable_id", "taggable_type", "tagger_id", "tagger_type") VALUES (?,?,?,?,?,?,?) [["context", "tags"], ["creation_at", пт, 28 сентября 2012 05:39:59 UTC +00: 00], ["tag_id", 16], ["taggable_id", 13], ["taggable_ty pe", "Photo"], ["tagger_id", 1], ["tagger_ty pe", "User"]]
(2,4 мс) совершить транзакцию
2 ответа
Хорошо, это действительно странно, но я понял, как избежать этой проблемы.
Первое, что я сделал, - это создал шип-решение для проверки act_as_taggable_on, и это, похоже, сработало. Он состоял из двух классов моделей и все... и он работал, когда я тестировал его через консоль rails.
Поэтому я добавил форму, как у меня в приложении rails, и протестировал ее снова...
У меня была форма, которая была что-то вроде этого:
<div>
<%= form_for @photo, :html => { :class => "dialog" } do |f| %>
...
<%= f.label :title%>
<%= f.text_field :title, :class => "wide" %>
<%= f.label 'Tags' %>
<%= f.text_field :tag_list, :value => @tags %>
...
<%= f.submit button_text(@photo), :class => "btn btn-large btn-primary" %>
<%= f.submit "Cancel", :class => "btn btn-large" %>
</div>
И когда я реализовал это и протестировал, я получил 'Cannot mass assign:tag_list'
Я прочитал об изменениях в Rails 3.2.3, касающихся массового назначения, и решил не ставить под угрозу безопасность.
Поэтому я добавил в свой класс фото модель
attr_accessible :tag_list
Это решило ошибку, НО, когда я проверял это, я обнаружил, что дублирующиеся строки, где СЕЙЧАС появляются! Так что теперь ошибка воспроизводима!!
Я решил это, изменив форму так, чтобы я не связывал форму с объектом модели Photo.
Вот так:
<div>
<%= form_tag({:controller => "photos", :action => "create"}, :method => "post", :class => "dialog") do %>
...
<%= label_tag :title, 'Title'%>
<%= text_field_tag :title, nil, :class => "wide" %>
<%= label_tag :tag_list, 'Tags'%>
<%= text_field_tag :tag_list, nil, :class => "wide" %>
...
<%= submit_tag('Add', :class => "btn btn-large btn-primary") %>
<%= submit_tag("Cancel", :class => "btn btn-large") %>
</div>
Я также удалил attr_accessible:tag_list и изменил контроллер, чтобы принимать различные значения из формы.
@photo = current_user.photos.build(:title => params[:title],
...
)
@user.tag(@photo, :with => params[:tag_list], :on => :tags)
И это решило проблему!
Я сейчас попробую разобраться, почему именно это происходит!:)
Я знаю, что этому вопросу уже добрых пять лет, но это все еще происходит в Rails 5.1 с acts-as-taggable 4.0
и я просто хотел показать, как это решается для всех, кто имеет эту проблему.
Это очень просто исправить, и в ваших сильных параметрах в контроллере вы просто должны добавить tag_list: []
скорее, чем :tag_list
вот так:
def photo_params
params.require(:photo).permit(:title, tag_list: [])
end
Это перестает дублировать и пусто Taggings
от создания в базе данных, и вы можете использовать form_for
а не form_tag
<%= form_for @photo do |f| %>
<%= f.text_field :title %>
<%= f.text_field :tag_list %>
<%= f.submit %>
<% end %>