Edited at

ActiveRecordでINNER JOINするとsaveできなくなる(解決策あり)

More than 5 years have passed since last update.

ActiveRecordでクエリーを組み立てる時に、joinsメソッドを使ってINNER JOIN句を付けると、取ってきたレコードをsaveできなくなります。

その検証と、saveできるようにする、方法。

require 'logger'

require 'active_record'

# テーブル定義
class CreateShelves < ActiveRecord::Migration
def change
create_table :shelves
end
end

class CreateBooks < ActiveRecord::Migration
def change
create_table :books do |t|
t.integer :shelf_id
end
end
end

# モデル定義
class Shelf < ActiveRecord::Base
has_many :books
end

class Book < ActiveRecord::Base
belongs_to :shelf
end

# ActiveRecordのセットアップ
logger = Logger.new($stderr)
ActiveRecord::Base.logger = logger # SQLをログに出すようにする
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'

# テーブル作成
CreateShelves.new.change
CreateBooks.new.change

# レコード作成
shelf = Shelf.create
shelf.books << Book.new

# やっと本題
# これだとreadonlyになる
shelves = Shelf.joins(:books)
begin
shelves.first.save
rescue => err
logger.error "#{err.class} (#{err.message})" # => ActiveRecord::ReadOnlyRecord (ActiveRecord::ReadOnlyRecord)
end

# こうすればsaveできる
shelves = Shelf.joins(:books).readonly(false)
shelves.first.save # => true

save!じゃなくてsaveなのに例外を起こすからいやな感じですね。