Open1
whereは配列じゃない!concatを使用する際の注意点 & URL直打ち禁止の難易度高めver
Your ManagerのURL直打ちを禁止する記述が非常に難しかった。
もっとも難しかったのはtasks_controllerへの記述
def ensure_correct_user
# parmasでuser_idを取得(URLで遷移しようとしているユーザーのid)
# URLに入力されたユーザーが所属しているグループ一覧を取得するために
# group_usersテーブルよりparamsで取得したuser_idをもつグループを配列で取得しjoin_groupsへ格納
# join_groupsを展開してgroup_usersテーブルよりjoin_groupのgroup_idをもつユーザーを配列で取得しcolleague_usersへ格納 (このとき、重複するものがあればまとめる)
# colleague_usersの中にcurrent_userがいるか判定する
unless User.find_by(id: params[:user_id]).nil?
user = User.find(params[:user_id])
join_groups = GroupUser.where(user_id: user.id)
@colleague_users = []
join_groups.each do |join_group|
@colleague_users.concat GroupUser.where(group_id: join_group.group_id).to_a
end
@users = []
@colleague_users.each do |colleague_user|
@users.concat User.where(id: colleague_user.user_id).to_a
end
@users.uniq!
unless @users.include?(current_user)
redirect_to tasks_path(user_id: current_user.id)
end
else
redirect_to tasks_path(user_id: current_user)
end
end
かなり複雑になってしまったけどポイントは2つ
- where文を使用したあとのデータは配列ではない
ここで
GroupUser.where(user_id: user.id)
の戻り値は配列ではなく、配列ライクなものであることに注意
実際にはActiveRecord::Relationというオブジェクトで、ほぼ配列のようなもの。
これがあるおかげでwhereにはメソッドチェーンを使用することができる。
- concatメソッド
配列 other を自身の末尾に破壊的に連結します。
今回のようにeach文の中で配列の中身を蓄積したいときなどに使える。
array = [1, 2]
a = [3, 4]
array.concat a
p array # => [1, 2, 3, 4]
p a # => [3, 4] # こちらは変わらない
参考:
ただし、このconcatというメソッドは配列にしか使うことができない。
whereの戻り値は厳密には配列ではないので、wehreでは使用できない。
そのため、
.to_aで配列の形式にしてあげる
変数 = [] でなにもデータがはいっていないときでもエラーにならないようにしてあげる
これらを行う必要がある。
@users.uniq!
では、@usersに格納した配列データで重複するものを覗いている。