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内でちょちょいとやってくれるらしい。