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
なのに例外を起こすからいやな感じですね。