Eugene Kalenkovich
audience.except(&:can_see_this).each do |person|
# Please!
person.move(:closer)
end
test:
adapter: postgresql # mysql2
database: your_db_test
def concurrently processes = 10
processes.times do
fork do
yield
end
end
assert Process.waitall.map(&:last).all? &:success?
end
def concurrently processes = 10
processes.times do
fork do
yield
end
end
assert Process.waitall.map(&:last).all? &:success?
end
def concurrently processes = 10
processes.times do
fork do
yield
end
end
assert Process.waitall.map(&:last).all? &:success?
end
def concurrently processes = 10
ActiveRecord::Base.remove_connection
processes.times do
fork do
begin
ActiveRecord::Base.establish_connection
yield
rescue => e
puts "#{e.class.name}: #{e}" && exit 1
ensure
ActiveRecord::Base.remove_connection
end
end
end
ActiveRecord::Base.establish_connection
assert Process.waitall.map(&:last).all? &:success?
end
def concurrently processes = 10
ActiveRecord::Base.remove_connection
processes.times do
fork do
begin
ActiveRecord::Base.establish_connection
yield
rescue => e
puts "#{e.class.name}: #{e}" && exit 1
ensure
ActiveRecord::Base.remove_connection
end
end
end
ActiveRecord::Base.establish_connection
assert Process.waitall.map(&:last).all? &:success?
end
def concurrently processes = 10
ActiveRecord::Base.remove_connection
processes.times do
fork do
begin
ActiveRecord::Base.establish_connection
yield
rescue => e
puts "#{e.class.name}: #{e}" && exit 1
ensure
ActiveRecord::Base.remove_connection
end
end
end
ActiveRecord::Base.establish_connection
assert Process.waitall.map(&:last).all? &:success?
end
class Number < ActiveRecord::Base
# t.integer :value
end
describe Number do
it 'should have unique values' do
concurrently do
10.times do
Number.where(value: Number.count).first_or_create
end
end
Number.count.must_equal Number.select('distinct value').count
end
end
describe Number do
it 'should have unique values' do
concurrently do
10.times do
Number.where(value: Number.count).first_or_create
end
end
Number.count.must_equal Number.select('distinct value').count
end
end
describe Number do
it 'should have unique values' do
concurrently do
10.times do
Number.where(value: Number.count).first_or_create
end
end
Number.count.must_equal Number.select('distinct value').count
end
end
1) Failure:
test_0001_should_have_unique_values(Number) :
Expected: 49
Actual: 99
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (0.4ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
> Number.where(value: 3).first_or_create
Number Load (0.4ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (16.2ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (9.0ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.4ms) COMMIT
> Number.where(value: 3).first_or_create
Number Load (0.4ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
> Number.where(value: 3).first_or_create
Number Load (0.4ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
> Number.where(value: 3).first_or_create
Number Load (0.4ms) SELECT "numbers".* FROM "numbers" WHERE "numbers"."value" = 3 LIMIT 1
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO "numbers" ("value") VALUES ($1) RETURNING "id" [["value", 3]]
(0.5ms) COMMIT
class ValidatedNumber < ActiveRecord::Base
validates :value, uniqueness: true
end
describe ValidatedNumber do
it 'should have unique values' do
concurrently do
10.times do
ValidatedNumber.create{|r| r.value = ValidatedNumber.count}
end
end
unique = ValidatedNumber.select("distinct value").count
ValidatedNumber.count.must_equal unique
end
end
1) Failure:
test_0001_should_have_unique_values(ValidatedNumber):
Expected: 37
Actual: 96
> ValidatedNumber.create(value: 1)
(0.1ms) BEGIN
ValidatedNumber Exists (25.2ms) SELECT 1 AS one FROM "validated_numbers" WHERE "validated_numbers"."value" = 1 LIMIT 1
SQL (14.7ms) INSERT INTO "validated_numbers" ("value") VALUES ($1) RETURNING "id" [["value", 1]]
(0.7ms) COMMIT
> ValidatedNumber.create(value: 1)
(0.1ms) BEGIN
ValidatedNumber Exists (25.2ms) SELECT 1 AS one FROM "validated_numbers" WHERE "validated_numbers"."value" = 1 LIMIT 1
SQL (14.7ms) INSERT INTO "validated_numbers" ("value") VALUES ($1) RETURNING "id" [["value", 1]]
(0.7ms) COMMIT
class CreateConstrainedNumbers < ActiveRecord::Migration
def change
create_table :constrained_numbers do |t|
t.integer :value
end
add_index :constrained_numbers, :value, unique: true
end
end
class CreateConstrainedNumbers < ActiveRecord::Migration
def change
create_table :constrained_numbers do |t|
t.integer :value
end
add_index :constrained_numbers, :value, unique: true
end
end
# Running tests:
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
[...]
# Running tests:
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
ActiveRecord::RecordNotUnique: PG::Error: ERROR: duplicate key value violates unique constraint "index_constrained_numbers_on_value"
DETAIL: Key (value)=(0) already exists.
: INSERT INTO "constrained_numbers" ("value") VALUES ($1) RETURNING "id"
[...]
class SafeNumber < ActiveRecord::Base
def self.first_or_create_where(*args)
where(*args).first_or_create
rescue ActiveRecord::RecordNotUnique
retry
end
end
class SafeNumber < ActiveRecord::Base
def self.first_or_create_where(*args)
where(*args).first_or_create
rescue ActiveRecord::RecordNotUnique
retry
end
end
# Running tests:
.
Finished tests in 8.337332s, 0.1199 tests/s, 0.2399 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
ActiveRecord::StatementInvalid: Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: INSERT INTO `safe_numbers` (`value`) VALUES (132)
ActiveRecord::StatementInvalid: Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: INSERT INTO `safe_numbers` (`value`) VALUES (132)
F
ActiveRecord::StatementInvalid: Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: INSERT INTO `safe_numbers` (`value`) VALUES (132)
ActiveRecord::StatementInvalid: Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: INSERT INTO `safe_numbers` (`value`) VALUES (132)
F
def self.first_or_create_where(*args)
where(*args).first_or_create
rescue ActiveRecord::RecordNotUnique
retry
rescue ActiveRecord::StatementInvalid => e
retry if e.message =~ /Deadlock/
# Thank you, MySQL and Mysql2!
raise
end
def self.first_or_create_where(*args)
where(*args).first_or_create
rescue ActiveRecord::RecordNotUnique
retry
rescue ActiveRecord::StatementInvalid => e
retry if e.message =~ /Deadlock/
# Thank you, MySQL and Mysql2!
raise
end
# Running tests:
.
Finished tests in 3.234423s, 0.3092 tests/s, 0.6183 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
class Dog < ActiveRecord::Base
has_one :head
has_many :legs
end
class Head < ActiveRecord::Base
belongs_to :dog
end
class Leg < ActiveRecord::Base
belongs_to :dog
end
20.times{ Dog.create }
concurrently do
begin
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && headless.create_head
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && legless.legs = 4.times.map{ Leg.create }
end while headless || legless
end
20.times{ Dog.create }
concurrently do
begin
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && headless.create_head
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && legless.legs = 4.times.map{ Leg.create }
end while headless || legless
end
20.times{ Dog.create }
concurrently do
begin
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && headless.create_head
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && legless.legs = 4.times.map{ Leg.create }
end while headless || legless
end
20.times{ Dog.create }
concurrently do
begin
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && headless.create_head
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && legless.legs = 4.times.map{ Leg.create }
end while headless || legless
end
Dog.all_str.must_equal "20 dogs with 1 head and 4 legs"
--- expected
+++ actual
@@ -1 +1 @@
-"20 dogs with 1 head and 4 legs"
+"3 dogs with 1 head and 8 legs, 2 dogs with 2 heads and 28 legs, 2 dogs with 1 head and 12 legs, 1 dog with 1 head and 4 legs, 1 dog with 4 heads and 24 legs, 1 dog with 4 heads and 32 legs, 1 dog with 3 heads and 16 legs, 1 dog with 2 heads and 32 legs, 1 dog with 1 head and 16 legs, 1 dog with 6 heads and 8 legs, 1 dog with 1 head and 20 legs, 1 dog with 2 heads and 16 legs, 1 dog with 4 heads and 36 legs, 1 dog with 5 heads and 24 legs, 1 dog with 8 heads and 20 legs, 1 dog with 2 heads and 40 legs"
--- expected
+++ actual
@@ -1 +1 @@
-"20 dogs with 1 head and 4 legs"
+"3 dogs with 1 head and 8 legs, 2 dogs with 2 heads and 28 legs, 2 dogs with 1 head and 12 legs, 1 dog with 1 head and 4 legs, 1 dog with 4 heads and 24 legs, 1 dog with 4 heads and 32 legs, 1 dog with 3 heads and 16 legs, 1 dog with 2 heads and 32 legs, 1 dog with 1 head and 16 legs, 1 dog with 6 heads and 8 legs, 1 dog with 1 head and 20 legs, 1 dog with 2 heads and 16 legs, 1 dog with 4 heads and 36 legs, 1 dog with 5 heads and 24 legs, 1 dog with 8 heads and 20 legs, 1 dog with 2 heads and 40 legs"
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.legs = Leg.all.sample(4)
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
Leg Load (0.2ms) SELECT "legs".* FROM "legs"
Leg Load (0.3ms) SELECT "legs".* FROM "legs" WHERE "legs"."dog_id" = 1
(0.1ms) BEGIN
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 6
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 3
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 10
(0.1ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 5
(0.5ms) COMMIT
> Dog.first.legs = Leg.all.sample(4)
Dog Load (0.4ms) SELECT "dogs".* FROM "dogs" LIMIT 1
Leg Load (0.3ms) SELECT "legs".* FROM "legs"
Leg Load (0.3ms) SELECT "legs".* FROM "legs" WHERE "legs"."dog_id" = 1
(0.1ms) BEGIN
SQL (0.3ms) UPDATE "legs" SET "dog_id" = NULL WHERE "legs"."dog_id" = 1 AND "legs"."id" IN (10, 5)
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 2
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 9
(0.6ms) COMMIT
> Dog.first.legs = Leg.all.sample(4)
Dog Load (0.4ms) SELECT "dogs".* FROM "dogs" LIMIT 1
Leg Load (0.3ms) SELECT "legs".* FROM "legs"
Leg Load (0.3ms) SELECT "legs".* FROM "legs" WHERE "legs"."dog_id" = 1
(0.1ms) BEGIN
SQL (0.3ms) UPDATE "legs" SET "dog_id" = NULL WHERE "legs"."dog_id" = 1 AND "legs"."id" IN (10, 5)
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 2
(0.2ms) UPDATE "legs" SET "dog_id" = 1 WHERE "legs"."id" = 9
(0.6ms) COMMIT
unique.fix :db, diy: true, mysql: mysql?
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && Dog.transaction do
headless.lock!
headless.create_head
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && Dog.transaction do
legless.lock!
legless.legs = 4.times.map{ Leg.create }
end
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && Dog.transaction do
headless.lock!
headless.create_head
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && Dog.transaction do
legless.lock!
legless.legs = 4.times.map{ Leg.create }
end
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
--- expected
+++ actual
@@ -1 +1 @@
-"50 dogs with 1 head and 4 legs"
+"30 dogs with 1 head and 4 legs, 11 dogs with 2 heads and 4 legs, 4 dogs with 3 heads and 4 legs, 4 dogs with 4 heads and 4 legs, 1 dog with 5 heads and 4 legs"
> Dog.first.create_head
Dog Load (0.3ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (12.0ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", 1]]
(0.9ms) COMMIT
Head Load (0.2ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.2ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 1
(0.4ms) COMMIT
> Dog.first.head = Head.create
Dog Load (39.8ms) SELECT "dogs".* FROM "dogs" LIMIT 1
(0.1ms) BEGIN
SQL (49.1ms) INSERT INTO "heads" ("dog_id") VALUES ($1) RETURNING "id" [["dog_id", nil]]
(0.6ms) COMMIT
"replace"
Head Load (0.4ms) SELECT "heads".* FROM "heads" WHERE "heads"."dog_id" = 1 LIMIT 1
(0.1ms) BEGIN
(0.4ms) UPDATE "heads" SET "dog_id" = NULL WHERE "heads"."id" = 2
(0.2ms) UPDATE "heads" SET "dog_id" = 1 WHERE "heads"."id" = 3
(0.5ms) COMMIT
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
headless && Dog.transaction do
headless.lock!
headless.head = Head.create
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
legless && Dog.transaction do
legless.lock!
legless.legs = 4.times.map{ Leg.create }
end
# Running tests:
.
Finished tests in 2.527906s, 0.3956 tests/s, 0.7912 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
if headless
headless.create_head
Head.update_all({ dog_id: nil },
{ id: Head.where(dog_id: headless.id).order(:id).pluck(:id)[0..-2] })
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
if legless
legless.legs = 4.times.map{ Leg.create }
Leg.update_all({ dog_id: nil },
{ id: Leg.where(dog_id: legless.id).order(:id).pluck(:id)[0..-5] })
end
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
if headless
headless.create_head
Head.update_all({ dog_id: nil },
{ id: Head.where(dog_id: headless.id).order(:id).pluck(:id)[0..-2] })
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
if legless
legless.legs = 4.times.map{ Leg.create }
Leg.update_all({ dog_id: nil },
{ id: Leg.where(dog_id: legless.id).order(:id).pluck(:id)[0..-5] })
end
headless = Dog.includes(:head).where(heads: {dog_id: nil}).first
if headless
headless.create_head
Head.update_all({ dog_id: nil },
{ id: Head.where(dog_id: headless.id).order(:id).pluck(:id)[0..-2] })
end
legless = Dog.includes(:legs).where(legs: {dog_id: nil}).first
if legless
legless.legs = 4.times.map{ Leg.create }
Leg.update_all({ dog_id: nil },
{ id: Leg.where(dog_id: legless.id).order(:id).pluck(:id)[0..-5] })
end
# Running tests:
.
Finished tests in 2.957711s, 0.3956 tests/s, 0.7912 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
remove_column :extra_columns, :extra
> ExtraColumn.create
(0.2ms) BEGIN
SQL (34.9ms) INSERT INTO "extra_columns" ("extra", "value") VALUES ($1, $2) RETURNING "id" [["extra", nil], ["value", nil]]
(0.2ms) ROLLBACK
ActiveRecord::StatementInvalid: PG::Error: ERROR: column "extra" of relation "extra_columns" does not exist at character 30
: INSERT INTO "extra_columns" ("extra", "value") VALUES ($1, $2) RETURNING "id"
> ExtraColumn.create
(0.2ms) BEGIN
SQL (34.9ms) INSERT INTO "extra_columns" ("extra", "value") VALUES ($1, $2) RETURNING "id" [["extra", nil], ["value", nil]]
(0.2ms) ROLLBACK
ActiveRecord::StatementInvalid: PG::Error: ERROR: column "extra" of relation "extra_columns" does not exist at character 30
: INSERT INTO "extra_columns" ("extra", "value") VALUES ($1, $2) RETURNING "id"
def columns
@columns ||= connection.schema_cache.columns[table_name].map do |col|
col = col.dup
col.primary = (col.name == primary_key)
col
end
end
class ExtraColumn < ActiveRecord::Base
def self.columns
@my_columns ||= super.reject{ |c|
c.name == 'extra'
}
end
end
remove_column :extra_columns, :extra
config.action_controller.asset_host = "//your.super.asset.host"
config.assets.digest = true
Concurrency of development with deployment . . . has almost always proven counterproductive
Harold Brown
I Can Haz Four Volunteers?
Rails is omakase. A team of chefs picked out the ingredients, designed the APIs, and arranged the order of consumption on your behalf according to their idea of what would make for a tasty full-stack framework.
DHH