LoginSignup
44
39

More than 3 years have passed since last update.

[Rails]newメソッド,saveメソッド,buildメソッド,createメソッドの違いについて勉強してみた

Last updated at Posted at 2020-11-10

Railsと日々格闘している「超」がつく初心者です。
自分自身の知識の整理のために、共有します。

オブジェクトを作成する系のメソッドって何か多くない?

テキストを流し読みしていると、なかなかこの事実に気付かなかったのですが、先日
「あれっ、newメソッドかと思ったら、ここではcreateメソッドを使うのか...
ってかよく考えたら、buildとかもあるよな...What?!」
という状態になってしまったので、自分なりに調べてみようと思いました。
短い記事ですが、最後までお付き合いください。
image.png

newメソッド & saveメソッドについて

まずは、newメソッドの基本的な使用方法から。
ちなみに、Bookモデルで投稿する前提で書いています。

books_controller
def new
  @book = Book.new
end

Book.newでBookクラスの空のインスタンスを作り、@bookインスタンス変数へ代入しています。
「こんなの誰でも知ってるよ」
かつての僕もそう思っていたのですが、何とnewメソッドで引数を指定する方法がありました。
それがこちら

books_controller
def new
  @book = Book.new(title: "羅生門", author:"芥川龍之介")
# titleを「羅生門」、authorを「芥川龍之介」としています。
end

これでbookの新規投稿を行うと、入力欄にいかなる文字を入力しようとも、羅生門以外に登録できなくなってしまいますが(笑)
newメソッドは、空のインスタンスを渡すだけではなかったのです。
知ってた人はすみません。

newメソッドの後は、createアクションでsaveメソッドを使用し、データを保存しにかかります。
それがこちら

books_controller
def create
  @book = Book.new(book_params)
  @book.save
end

これでようやく、Bookのデータベースに新規登録することが出来ました。
saveメソッドの場合は、newメソッドとセットでデータベースに保存できます。

createメソッドについて

ここで噂のcreateメソッドが登場します。
上述のnewメソッド、saveメソッドを使って保存してきたステップを、createメソッドならわずか1行で終わらせることが出来ます。

どういうことかというと、

books_controller
def create
  Book.create(title: "羅生門", author:"芥川龍之介")
end

これだけで、データベースに保存することが出来ました。
データの保存だけではなく、モデルのインスタンス生成も同時に行えます。
メッチャ簡単。ラク。

基本構文
モデル名.create(カラム名: "値")

繰り返しになりますが、createメソッドは、newとsaveを同時に行っているメソッドということです。

それなら、createメソッドだけ使うことにしたら良いのでは?
という浅はかな考えが沸き起こりそうですが、そう甘くはありません。

どのように使い分けるべきか

生成したインスタンスを使って何かしらの操作を行いたい場合には、createメソッドは使用できないので、newメソッドとsaveメソッドを記述する形になります。
具体的に、
1. ifを利用して条件分岐を作りたい時
2. renderでエラーメッセージを出したい時
などがあり、下記で説明します。

❶ifを利用した条件分岐

users_controller.rb
def create
  @user = User.new(user_params) #インスタンス変数を作成
  if @user.save
    redirect_to @user, notice: 'ユーザー作成完了'
  else
    render :new #saveできなかった時のrender先
  end
end

このように、インスタンス変数を利用して、成功パターンと失敗パターンに分けるなど、条件分岐が発生する場合は、newメソッドとsaveメソッドを使用することになります。

❷renderでエラーメッセージを出したい

例えば、新規投稿を行う画面(newアクション)で、バリデーションチェックが働いて、投稿できなかったとします。
その際に、投稿欄の上にエラーメッセージが出たら、非常にわかりやすいですよね。
具体的に説明します。

books_controller
def new
  @book = Book.new
end

def create
  @book = Book.new(params[:id])
  if  @book.save
      redirect_to book_path(@book.id)
  else
      render 'layouts/errors'
  end
end
views/books/new.html.erb
<h1>New Book</h1>
<%= render 'layouts/errors', obj: @book %>
#省略
layouts/_errors.html.erb
<% if obj.errors.any? %>  #objに@bookを代入
  <div id="error_explanation">
    <h3><%= pluralize(obj.errors.count, "error") %> prohibited this obj from being saved:</h3>

    <ul>
    <% obj.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
    </ul>
  </div>
<% end %>

上記のように、newメソッドが入ったインスタンス変数を使用して、エラーメッセージを出す時にも、createメソッドだけでは不可能です。
なんか、色々と考えないといけないことが多いですね...

buildメソッドについて

いよいよ最後のメソッドです。
しかしながら、重要度としては一番低いと思います。
現行のrailsでは、newメソッドとbuildメソッドはほとんど同じ働きをするからです。
古いバージョンのrailsでは、関連付けがされている時に、自動的に外部キーが付くかどうか、という違いがあったのですが、今はnewメソッドもbuildメソッドも外部キーがセットされます。
職場によっては、特定の場面でbuildを推奨しているケースもあるとのことですが、そうじゃなければ、newメソッドに一本化しても問題ないでしょう。

おわりに

今回も非常に勉強になることばかりでした。
「これは流石に分かってるわ」と思うようなことでも、深掘りをすればするほど、新しい発見があります。
これからも精進して勉強に勤しみます。

44
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
39