LoginSignup
34
44

More than 5 years have passed since last update.

ネストとアソシエーション

Last updated at Posted at 2018-11-12

ネスト

ネストとは入れ子構造とも呼ばれ、ある記述の中に入れ子構造で別の記述をする方法です。
ルーティングでいうと、あるコントローラへのルーティングの記述の中に、別のコントローラへのルーティングを記述するということを指します。

Q.そもそもネストは何のために使うの?
A.コメント機能を実装する際に、どのツイートに対するコメントなのかをパスから判断できるようにするため

pictweetでルーティングをネストさせる一番の理由はアソシエーション先のレコードのidをparamsに追加してコントローラに送るためです。今回の場合、コメントと結びつくツイートのidをparamsに追加している。

<ネスト使用前>

routes.rb
resources :tweets
resources :comments, only: [:create]
resources :users, only: [:show]

rake routesで中身を見ると、、、
comments POST /comments(.:format)
→この状態だと、どのツイートに対するコメントなのかが分からない。

<ネスト使用後(ネストした箇所をdo 〜 endで囲む)>

routes.rb
resources :tweets do
  resources :comments, only: [:create]
end
resources :users, only: [:show]

rake routesで中身を見ると、、、
tweet_comments POST /tweets/:tweet_id/comments(.:format)
→どのツイートに対するコメントかが分かる。ここでは「:tweet_id」に対するコメントであることが分かる。
実際のツイートの詳細画面のURLは下記のようになっている。

http://localhost:3000/tweets/11
よって、この詳細画面でコメントをすると、下記のようなURLになる。
http://localhost:3000/tweets/11/comments
以上より、ネストを実施することで tweetsのidが「11」のツイートに対してコメントをするということが分かる。

アソシエーション

モデル間の関連付け(主従関係)を管理する機能のことで、定義しておくことでモデルをまたいだデータの呼び出しをより簡単に行うことができるようになります。

<重要>
モデルが複数生成された時点で、「各モデル間で主従関係はどうなっているのか」は意識的に見ておくこと。
つまり、has_manyなのかbelongs_toのいずれの関係になっているのかを明確にさせておくこと。モデルが増えれば増えるほど、この主従関係がややこしくなってくるはずなので先に考えていた方がベター。後の呼び出しも楽になる。

1.アソシエーションを定義する

・モデルクラスにhas_many , belongs_toを定義
■has_many : 〜〜
→記述しているモデルクラスは〜〜を複数保有している(一対多の関係)

@tweets = current_user.tweets.page(params[:page]).per(5).order("created_at DESC")
→現在ログイン中のユーザー(current_user)が保有しているtweets情報(.tweets)をインスタンスとして「全て」取得

current_userには、現在ログインしているユーザーのレコード1つがuserクラスのインスタンスとして入っている。よって、上記の記述によって、現在ログインしているユーザーの投稿したツイート全てを取得することができる。
※tweetsが複数形になっていることに注目。これはuserとtweetsが「一対多の関係」なので、複数形になっている。これが単数形だとインスタンスを呼び出せない。

■belongs_to : 〜〜
→記述しているモデルクラスは〜〜に帰属している、紐付いて複数の情報が存在している。
tweet = Tweet.find(1)
tweet.user
usersテーブルに対して、idがtweet(インスタンス変数)のuser_idと等しいレコードを取得。

2.アソシエーションを実装する

【アソシエーション未使用】
user = User.find(1)
Tweet.where(user_id: user.id)

【アソシエーション使用】
user = User.find(1)
user.tweets

<意味>
usersテーブルのidが「1」のレコードをuserという変数に代入
つまり、userはuserクラスから生成された「インスタンス」
よって、user.tweetsという記述が可能になり、ここではusersテーブルのidが「1」のユーザーが保有している(投稿している)ツイート(tweets)を「全て」取得する、という記述になっている。
両方意味は同じだが、分かりやすさ・読みやすさが一目瞭然。

これだと直感的に分かりやすい。

sample.rb
<%= tweet.user.nickname %>

tweetのuser_idと同じidを持つユーザーのnicknameを取得している。
もっと簡単に言うと、このtweetを投稿したユーザーのnicknameを取得している。
何回も読んで直感的に理解できるようにしよう

【include】
includes(:モデル名)で使われるメソッド(コントローラクラスで使われる)
→これを使うことによって、データの処理回数が減り、ページの遷移のスピードが早くなる。SQLサーバに負担をかけすぎるとサーバートラブルが発生したり、ページ遷移のスピードが遅くなる。includesメソッドは開発側もユーザーも双方とっても利便性が上がるので、使った方が良い。基本的にアソシエーションと一緒に使うというイメージで問題なし。
def index
 @tweets=Tweet.includes(:user).page(params[:page]).per(5).order("created_at DESC")
end
上記のように、使いたいインスタンスメソッド内で、記述することで、そのインスタンスメソッド内だけで適応される。

34
44
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
34
44