問題を少し再構築して、has_and_belongs_to_many
関連付けを関連付けに置き換えてみましょう。次のように、モデルに別の関連付けhas_many, through
を追加します。has_many, through
Character
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
end
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
has_many :characters
end
class Character < ActiveRecord::Base
belongs_to :user
has_many :groups, through: :user
end
モデルは、とMembership
の間の関係を表したものです。基本的には、 を使用すると非表示になる結合テーブルです。私はその関係を見ることを好みます (特にそれが重要な場合)。User
Group
has_and_belongs_to_many
Character
モデルには、ユーザーに関連付けられた への関連付けもGroup
あります。これは、スコープに参加しようとするときに役立ちます。
モデルを肉付けしCharacter
て、以下を追加しましょう。
sifter :by_user do |user|
user_id == user.id
end
sifter :public do
public
end
シフターをビルディングブロックとして使用して、次を追加して、(定義したとおりに)表示される文字を取得できます。
def self.get_visible(user)
Character.uniq.joins{groups.outer}.where{(sift :public)|(sift :by_user, user)|(groups.id.in(user.groups))}
end
このメソッドは のインスタンスを取り、User
次の を検索しますCharacter
。
- 公開キャラ全員。
- すべてのユーザーの文字。
- ユーザーのグループに属するすべての文字。
そして、これらのセットから個別の文字リストのみを取得します。
Rails コンソールから:
irb(main):053:0> Character.get_visible(User.find(4))
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 4]]
Group Load (0.7ms) SELECT "groups".* FROM "groups" INNER JOIN "memberships" ON "groups"."id" = "memberships"."group_id" WHERE "memberships"."user_id" = 4
Character Load (0.9ms) SELECT DISTINCT "characters".* FROM "characters" LEFT OUTER JOIN "users" ON "users"."id" = "characters"."user_id" LEFT OUTER JOIN "memberships" ON "memberships"."user_id" = "users"."id" LEFT OUTER JOIN "groups" ON "groups"."id" = "memberships"."group_id" WHERE ((("characters"."public" OR "characters"."user_id" = 4) OR "groups"."id" IN (2)))
[
[0] #<Character:0x00000005a16b48> {
:id => 4,
:user_id => 4,
:name => "Testiculies",
:created_at => Tue, 13 Aug 2013 14:35:50 UTC +00:00,
:updated_at => Tue, 13 Aug 2013 14:35:50 UTC +00:00,
:public => nil
},
[1] #<Character:0x00000005d9db40> {
:id => 1,
:user_id => 1,
:name => "conan",
:created_at => Mon, 12 Aug 2013 20:18:52 UTC +00:00,
:updated_at => Tue, 13 Aug 2013 12:53:42 UTC +00:00,
:public => true
}
]
特定の文字が持つすべての文字を見つけるには、モデルUser
にインスタンス メソッドを追加します。User
def get_visible_characters
Character.get_visible(self)
end
行きたいところに行けると思います。