ruby チュートリアル 14章メモ
ActiveRecord through
n:mの関係を表すのに使用。1:nの関係はhas_many
とbelongs_to
で表した。また後者の繋ぎ方であると、直接的な結びつきになるのに対して、throughを使用する場合は、2モデル間にクッションとなるモデルを定義してそこに関係をしまっていくイメージ。チュートリアルではユーザ間のフォローに使用して、誰が誰をフォローしているかを表すために使用。
userに追加する
user
モデルと新たに作成したrelationship
モデルに関係性を追記する。
# app/models/user.rb class User < ApplicationRecord has_many :microposts, dependent: :destroy # micropostは外部キーがuser_idであったためこれでok has_many :active_relationships, class_name: "Relationship", #外部キーはfollower_idとして定義しなければならない(followerというクラスは存在しない) foreign_key: "follower_id", dependent: :destroy ... end
# app/models/relationship.rb class Relationship < ApplicationRecord belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User" end
定義されるメソッド
active_relationship.follower フォロワーを返します
active_relationship.followed フォローしているユーザーを返します
user.active_relationships.create(followed_id: other_user.id) userと紐付けて能動的関係を作成/登録する
user.active_relationships.create!(followed_id: other_user.id) userを紐付けて能動的関係を作成/登録する (失敗時にエラーを出力)
user.active_relationships.build(followed_id: other_user.id) userと紐付けた新しいRelationshipオブジェクトを返す
非同期通信
form_with
を使用して非同期通信を行う場合、remote:true
を指定してあげることで非同期通信となる。一つ注意としては、form_with
ではデフォルトでremote:true
が設定されている。(前身のform_for
ではデフォルトではなく明示的に指定が必要であった) なので、非同期にしたくない場合にlocal:true
を指定してあげることを忘れないようにする。
Unobtrusive Javascript
RailsではJS
を前面に出さないようにする習わしがあるらしい。
http://railscasts.com/episodes/205-unobtrusive-javascript
respond_to
コントローラ内で使用した。リクエストで指定されたフォーマットでレスポンスを返すためのメソッド。
respond_to do |format| format.html { redirect_to @user } format.js end
例えばこれがcreate
メソッド内で呼ばれているのであれば、views/対応するモデル複数名/create.js.erb
がJS
でのレスポンスの際に呼ばれるファイルとなる。
にしてもこの記事は酷いと思う。 => https://techacademy.jp/magazine/17744
Ajaxのテスト(RSpec)
RSpecでajaxフォームのテストを行うにはxhr
を追記してあげる。具体的には下。
xhr :get ~~~
model間のRailsの予測
# models/user.rb has_many :followeds, through: :active_relationships
上の1行をみて、rails
はactive_relationships
のfollowed_id
を使って対象ユーザを取得しようとする(複数形を単数形にする).
自分でカラムを指定する場合、自分で名前を指定したい場合は下のように書く。
has_many :following, through: :active_relationships, source: :followed
followed
+_id
カラムを対象とし、user
モデル内で呼び出すときはfollowing
という名前で呼び出すことが可能。
個人的なメモ
# /models/user.rb has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy has_many :following, through: :active_relationships, source: :followed
上のコードがuser
モデルに書いてあることで、follower_id
とfollowed_id
のカラム(どちらもUserモデルにbelongs_to
)をもつRelationship
モデルから、user.following
で、relationshipのfollowedにあるid(userがフォローしているアカウント)が配列で取得できる。鍵になっているのが上の定義で、active_relationships
を呼ぶことで、関連付いている自分のid
とfollower_id
を頼りに、関係あるデータだけを取得してきている。よって、下のfollowing
の定義では実質”関係あるデータの中から”のみデータを探索することができている。(下の定義だけ見てては、どうやって自分に関係あるレコードを抽出している理解できず、困惑していた)
memberとcollection
config/route
内でresources
を使用してルーティングを設定するとき、collection
メソッドを使用すると、resources
で設定したルーティングにつけ加わる感じで、新たなアクション&ルーティングを定義できる。
resources :users do collection do get :tigers end end
member
メソッドを使用すると特定のデータに対するアクションを生成することが可能になる。チュートリアルでは、ユーザのフォロー/フォロワーを表示するために使用。(~/users/1/following)
resources :users do member do get :following, :followers end end
map
rubyのmapメソッドは、列挙可能なオブジェクトを配列に変換してくれる。
[3] pry(main)> [1,2,3,4].map{|i| i.to_s} => ["1", "2", "3", "4"] [4] pry(main)> [1,2,3,4].map(&:to_s) #省略系 => ["1", "2", "3", "4"] [7] pry(main)> [1,2,3,4].map(&:to_s).join(",") => "1,2,3,4" [8] pry(main)>
チュートリアルではユーザがフォローしている人のidを取得するの使用
>> User.first.following.map(&:id) => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
ActiveRecordでは、下のようなメソッドも用意されていて全く同じ動きをする。これはhas_many :following
の関連付けを行った時に自動で生成され、+_ids
をつける形で実装される。
>> User.first.following_ids => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
サブクエリ
SELECT文のなかにSELECT文を記述する(括弧でくくる)。一般的に可読性はよくなる。チュートリアルでは効率をあげるためとの表記があった。これは、既存実装のfollowing_ids
を使用した場合、DBへのアクセスが二回発生するからとのこと。サブクエリとして自分で実装することで、DB内でちょちょいとやってくれるらしい。