Passionate Engineer
Passionate Engineer

Reputation: 10412

How would I save multiple records at once in Rails?

How would I save this array in one call with Rails?

tax_rates = [{
  :income_from => 0
  :income_to  => 18200
  :start => "01-07-2013"
  :finish => "30-06-2014"
  :rate => nil
  :premium => nil
  },{
  :income_from => 18201
  :income_to  => 37000
  :start => "01-07-2013"
  :finish => "30-06-2014"
  :rate => 0.19
  :premium => nil
  },{
    :income_from => 18201
    :income_to  => 37000
    :start => "01-07-2013"
    :finish => "30-06-2014"
    :rate => 0.19
    :premium => nil
    }]

Can I just call Rails.create(tax_rates)?

Also, is there a way to remove duplicate symbols so they look neater?

Upvotes: 20

Views: 33560

Answers (6)

apneadiving
apneadiving

Reputation: 115521

A nice solution is to use the active record import gem. I recommend it over now built-in Rails bulk insert because it's more flexible in the options in case of constraint violation.

TaxRate.import(
  [:income_from, :income_to, :start, :finish, :rate, :premium],
  tax_rates
)

Its definitely better than my old answer which would trigger a db commit per entry in the array :)


Old answer:

tax_rates.map {|tax_rate| TaxRate.new(tax_rate).save } 

This way you'll retrieve an Array with true or false to know which did succeed and which didn't.

Upvotes: 14

val caro
val caro

Reputation: 5

use a gem 'fast_inserter': https://github.com/joinhandshake/fast_inserter

it generates a single sql query of thousand records.

movie_data = [1, 'Climates (Iklimler)', 'Clay Pauwel', 'Drama'],
          [2, 'Tinpis Run', 'Andros Glazer', 'Comedy'],
          [3, 'Naked City, The', 'Bethena Chatband', 'Mystery'],
          [4, 'Small Time Crooks', 'Naomi Plom', 'Crime'],
          [5, 'Shadowboxer', 'Georgeanne Widdicombe', 'Thriller']

    params = {
      table: 'movies',
        static_columns: {
          created_at: '0000-00-00 00:00:00',
          updated_at: '0000-00-00 00:00:00',
        },
      options: {
        timestamps: false,
        unique: true,
        check_for_existing: true
      },
        group_size: 100,
        variable_columns: %w(id title director description),
        values: movie_data
    }
    inserter = FastInserter::Base.new(params)
    inserter.fast_insert

Upvotes: -2

user3209457
user3209457

Reputation: 111

I am not sure about rails < 4.2 but I have tried it in rails 4.2 you can simply do this

TaxRate.create(tax_rt)

Upvotes: 4

Dennis
Dennis

Reputation: 59499

Your example is almost correct.

Use ActiveRecord::Persistence#create, which can accept an array of hashes as a parameter.

tax_rates = [
  {
    income_from: 0,
    income_to: 18200,
    start: "01-07-2013",
    finish: "30-06-2014",
    rate: nil,
    premium: nil,
  },
  {
    income_from: 18201,
    income_to: 37000,
    start: "01-07-2013",
    finish: "30-06-2014",
    rate: 0.19,
    premium: nil,
  },
  # ...
]

TaxRate.create(tax_rates)  # Or `create!` to raise if validations fail

Upvotes: 29

skadoosh
skadoosh

Reputation: 481

If you want all of them to be saved .or, non of them to be saved even if one fails, you can use 'ActiveRecord::Base.transaction'

e.g.

ActiveRecord::Base.transaction do  
   tax_rate.each do |tax_rt|  
       TaxRate.new(tax_rt).save  
    end
 end

Upvotes: 7

kiriloff
kiriloff

Reputation: 26333

Here is an example like yours:

a = []

a << B.new(:name => "c")
a << B.new(:name => "s")
a << B.new(:name => "e")
a << B.new(:name => "t")

The array is saved all at once with:

a.each(&:save)

This will call B#save on each item in the array.

Upvotes: -1

Related Questions