流しのRails業でチームの中で共有したtipsをちょっとずつブログにも書いていくぞという。気持ち。
ちょっと初心者向けの話題のように思うかもしれないけれど、私もなんども苦しんだことなので。
$ rails g scaffold Book name:string price:integer
scaffoldでこのように生成したとしよう。
そうすると、BooksController#create
は以下のように生成される。
# POST /books
# POST /books.json
def create
@book = Book.new(book_params)
respond_to do |format|
if @book.save
format.html { redirect_to @book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: @book }
else
format.html { render :new }
format.json { render json: @book.errors, status: :unprocessable_entity }
end
end
end
もう少し簡易化してみましょう。
# POST /books
def create
@book = Book.new(book_params)
if @book.save
redirect_to @book, notice: 'Book was successfully created.'
else
render :new
end
end
respond_toを排除し、HTMLしか返さないようにしてみました。
何の変哲も無いcreateアクションに見えるでしょうが、これがrailsのcreateの基本形です。全てのPOSTをこの形で書けるようにすべきです。
例えば、Serviceクラスを使う時はこうなっていると綺麗です。
def create
if BookRegisterService.call(book_params)
redirect_to :show, notice: 'Book was successfully created.'
else
render :new
end
end
save
modelのインターフェースを委譲されたmodelでデコレーターパターンを用いて実装すると、もっと元の形に近いままです。
def create
@book = Manga.new(Book.new(book_params))
if @book.save
redirect_to @book, notice: 'Book was successfully created.'
else
render :new
end
end
MangaはBookクラスから委譲されたインターフェースを持っています。
class Manga
delegate_missing_to :@book
def initialize(book)
@book = book
end
def save
# Manga固有のロジックをここに書く
@book.save
end
end
Formオブジェクトも似たような形にできます。
def create
@book = BookForm.new(book_params)
if @book.save
redirect_to @book, notice: 'Book was successfully created.'
else
render :new
end
end
class BookForm
include ActiveModel::Model
attr_accessor :name, :price
def save
if valid?
# フォームが正しかった時の処理
true
else
false
end
end
end
とりあえず、今日はここまでにしておきます。