【Rails】Active Recordでオブジェクトを作ろう!(new/build)
Ruby on Railsでデータベースを操作するのに使うActive Record
。
今回は、new
やbuild
を使って実現するオブジェクトの作り方を紹介します。
基本的なこと
new
やbuild
は基本的に出来ることは一緒です。
厳密には違うのかもしれませんが、「new build 違い」でググってもあまりヒットしませんでした。(知っている方、ぜひ教えて下さい!)
ですが、使う場面が違ったりするのでそちらを以下で紹介できればと思います。
今回利用するテーブルはこちらです。
# users Table "public.users" Column | Type | Collation | Nullable | Default ------------------------+-----------------------------+-----------+----------+----------------------------------- id | integer | | not null | nextval('users_id_seq'::regclass) email | character varying | | not null | ''::character varying name | character varying | | | tel | character varying | | | postal_code | character varying | | | address | character varying | | | nickname | character varying | | | gender | character varying | | | birthday | date | | |
# posts Table "public.posts" Column | Type | Collation | Nullable | Default ------------+-----------------------------+-----------+----------+----------------------------------- id | bigint | | not null | nextval('posts_id_seq'::regclass) user_id | bigint | | | title | character varying | | | body | text | | | created_at | timestamp without time zone | | not null | updated_at | timestamp without time zone | | not null | Indexes: "posts_pkey" PRIMARY KEY, btree (id) "index_posts_on_user_id" btree (user_id) Foreign-key constraints: "fk_rails_5b5ddfd518" FOREIGN KEY (user_id) REFERENCES users(id)
# user_condition Table "public.user_conditions" Column | Type | Collation | Nullable | Default ---------------+-----------------------------+-----------+----------+--------------------------------------------- id | bigint | | not null | nextval('user_conditions_id_seq'::regclass) user_id | bigint | | | sign_in_count | integer | | not null | 0 created_at | timestamp without time zone | | not null | updated_at | timestamp without time zone | | not null | Indexes: "user_conditions_pkey" PRIMARY KEY, btree (id) "index_user_conditions_on_user_id" btree (user_id) Foreign-key constraints: "fk_rails_47c01ca983" FOREIGN KEY (user_id) REFERENCES users(id)
newを使う時
new
を使う時は、そのモデル単体で作成したい場合に使います。
Model.new
だけ実行すると空っぽの状態で、引数にカラムと設定したい値を付けると値が反映された状態で作成されます。
# 引数なし > user = User.new => #<User id: nil, email: "", created_at: nil, updated_at: nil, name: nil, phonetic: nil, tel: nil, postal_code: nil, address: nil, nickname: nil, gender: nil, birthday: nil> # 引数あり > User.new(name: 'opiyo', email: 'kosmo.waizu0804@gmail.com') => #<User id: nil, email: "kosmo.waizu0804@gmail.com", created_at: nil, updated_at: nil, name: "opiyo", .....>
実際の処理で使う場面としては、new
やcreate
アクションで使うと思います。
class UsersController < ApplicationController def new @user = User.new end def create @user = User.new user_params if @user.save redirect_to users_path else render :new end end private def user_params params.require(:user).permit(:name, :postal_code, :address, :email, :tel) end end
buildを使う時
build
を使う時は、1 : Nの関係がある時にN側のモデルを作成したい場合に使います。
# user.rb(1) class User < ApplicationRecord has_many :posts, dependent: :destroy end
# post.rb(N) class Post < ApplicationRecord belongs_to :user end
new
と同じで引数がないと空っぽの状態で、引数があるとその値が反映された状態で作成されます。
# 引数なし > user = User.last => #<User id: 1, email: "kosmo.waizu0804@gmail.com", created_at: "2019-04-04 09:26:02", updated_at: "2019-04-16 12:08:08", name: "opiyo" > user.posts.build => #<Post:0x00007faeee38dfe8 id: nil, user_id: 200, title: nil, body: nil, created_at: nil, updated_at: nil> # newでも同じことが出来ます > user.posts.new => #<Post:0x00007faeef94e350 id: nil, user_id: 200, title: nil, body: nil, created_at: nil, updated_at: nil>
実際の処理で使う場面としては、new
やcreate
アクションで使うのは同じですがログインが前提の場合や親になるモデルが取得できているような場面で利用します。
class ApplicationController < ActionController::Base def current_user @current_user = User.find_by(id: session[:user_id]) end end class PostsController < ApplicationController def new @post = @current_user.posts.build end def create @post = @current_user.posts.build post_params if @post.save redirect_to users_posts_path else render :new end end private def post_params params.require(:post).permit(:title, :body) end end
Post.new
してpost.user_id = @current_user.id
みたいに書くことも可能ですが、上記のように書くことで最初からuser_id
が設定された状態でオブジェクトが作られますのでスマートに書けます。
new/build以外の作り方
1 : 1の関係でオブジェクトを作りたい時はbuild_テーブル名
というメソッドを使います。
# user.rb(1) class User < ApplicationRecord has_one :user_condition, dependent: :destroy end
# user_condition.rb(1) class UserCondition < ApplicationRecord belongs_to :user end
> user = User.last => #<User id: 200, email: "kosmo.waizu0804@gmail.com", created_at: "2019-04-04 09:26:02", updated_at: "2019-04-16 12:08:08", name: "opiyo"...> > user.user_condition UserCondition Load (0.5ms) SELECT "user_conditions".* FROM "user_conditions" WHERE "user_conditions"."user_id" = $1 LIMIT $2 [["user_id", 200], ["LIMIT", 1]] => nil # newだとエラー > user.user_condition.new NoMethodError: undefined method `new' for nil:NilClass from (pry):6:in `<main>' # buildだとエラー > user.user_condition.build NoMethodError: undefined method `build' for nil:NilClass from (pry):7:in `<main>' > user.build_user_condition => #<UserCondition:0x00007feedc2c26d0 id: nil, user_id: 200, sign_in_count: 0, created_at: nil, updated_at: nil>
まとめ
最後に改めてざっとまとめてみると、こんな感じでしょうか。
- 単体でオブジェクトを作る時は
Model.new
- 1 : Nの関係の時は
parent.childs.build
- 1 : 1の関係の時は
model.build_テーブル名
では。