0

I need to save a large number of posts with a translated body attribute, so I'm trying to use insert_all/upsert_all in conjunction with Mobility. Saving posts individually works just fine:

Post.create({
  body_en: "Hello world",
  body_ja: "ハロー・ワールド",
  ...
})

However, trying to use insert_all results in an error since body is not stored in the posts table, but rather in mobility_text_translations table related via a polymorphic association (I'm using the default key/value backend):

posts = []

# In a loop, add many posts to the posts array
post = {
  body_en: "Hello world",
  body_ja: "ハロー・ワールド".
  ...
}

posts << post

# Add posts to DB at some interval
Post.insert_all(posts)
# => unknown attribute 'body_en' for Post. (ActiveModel::UnknownAttributeError)

I think this is somewhat similar to ActionText, where instead of ActionText::RichText.insert_all(post_bodies) I wonder if we could do something like Mobility::TextTranslations.insert_all(post_bodies). However, I don't see this capability discussed on the GitHub page nor in the issues.

baka-san
  • 111
  • 2
  • 8

1 Answers1

0

This behavior is because Mobility handles a single entry when you call create, as follows -

  1. The before_save callback fires;
  2. If the model does not have an attribute, for example body_fr, then it is removed from the list for the entry, and instead an entry is created in the Mobility table for the body attribute and the fr locale with a link to the main entry in the posts table.

Performing bulk operations in ActiveRecord does not trigger this callback. So, if you want to improve speed of inserting or updating many records, you can wrap iteration about data inside transaction.

data = [{body_en: 'aaa', body_fr: 'aaa'}, {body_en: 'bbb', body_fr: 'bbb'}]
::ActiveRecord::Base.transaction do
  data.each do |post|
    Post.create(post)
  end
end
Sergio Belevskij
  • 2,478
  • 25
  • 24