2012-05-13 3 views
1

has_many関係の間に追加のプロパティを追加することを検討していました。has_many関係で使用すると、結合テーブルの余分な属性にアクセスする

たとえば、私はUsersテーブルとGroupテーブルを持っています。ユーザーは:through has_many関係でグループに参加できます。私はそのグループのユーザーの '役割'のプロパティを追加したいと思います。

create_table "groupization", :force => true do |t| 
    t.integer "user_id" 
    t.integer "group_id" 
    t.string "role" 
    t.datetime "created_at",      :null => false 
    t.datetime "updated_at",      :null => false 
    end 

私はどのようにロール属性にアクセスできますか。私のような何かを考えていた:

user.groups[0].role 

をことは正しいアプローチですか?私は構文が間違っていることを知っている(私はそれを試した);正しい構文はどのようなものでしょうか?ありがとう!

答えて

2

は、あなたのようなものがあるでしょう。

foo = User.first 
bar = foo.groupizations.first 
bar.role 

最初のユーザーがグループ化されているとします。

特定のユーザー/グループの関係は次のように行うことができる行き方:

Groupizations.where("group_id = ? and user_id = ?", group.id, user.id) 

するとそこから、あなたが探していた役割を得ることができます。

3

私はこれを行うにはエレガントな方法があると思う、このようなだけで何かしていない:あなたが示したので、もしあなたが[0]を与えたサンプルコードは、現実的な使用のように見えるしていません

user.groupizations.find_by_group_id(user.groups[0].id).role 

私たちはあなたが実際にroleにアクセスしたいと思っていたが、よりクリーンな方法かもしれない。

これはhereを議論しました。

+0

これは 'user.groupizations.find_by_group_id(user.groups.first).role'に少し簡略化できると思います。 Rails 3.1以降では、 '#first'を使うとより速くなるはずです。なぜなら'#[] 'はすべてのレコードを強制的に取り出すのに対し、単一の行を検索するからです。 –

+0

はい、私はもともと 'user.groups.first'を持っていましたが、私は、ニュートンがどのようにグループにアクセスしていたかに沿ってそれを変更しました。しかし、私が言ったように、なぜこのように最初のグループだけの「役割」が任意にアクセスされるのか想像できません。 –

+0

私は不明であったと思う。単純化は '.id'の省略です。通常はモデルインスタンスをファインダ引数として渡すことができ、ActiveRecordはそのインスタンスからid値を使用する必要があることを認識します。 –

1

それはあなたが正確に何を探しているはっきりしないので、私はそれが起こって何それがより明確にするためにコンソール出力を別の例を捨てるでしょう。しかし、ユーザーの役割だけを取得するには、ユーザーのグループのどれを意味するかを指定する必要があります(@BuckDoyleのように、最初のものを選択して例を反映させます) 。すべてのユーザーの役割のリストを取得するには、ユーザーのグループ化を反復処理する必要があります。

1.9.3-p194 :050 > User.find_by_name("Homer").groupizations.each {|groupization| 
       puts groupization.group.org + ': ' + groupization.role} 

User Load (2.8ms) SELECT "users".* FROM "users" WHERE "users"."name" = 'Homer' LIMIT 1 
Groupization Load (1.5ms) SELECT "groupizations".* FROM "groupizations" WHERE 
"groupizations"."user_id" = 2 

Group Load (1.9ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 1 
LIMIT 1 

The Movementarians: cult follower 

Group Load (1.4ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 2 
LIMIT 1 

Nuclear Plant: employee 

最後に一つの思想(些細な1種)「groupizations」は確かに動作しますが、「役割」の場合のみ、より具体的な関係モデルを命名、追加しようとしている属性(「メンバーシップ」と言います)少なくとも私の経験では、関係が少し明確になるという点で実用的な利点があります。あなただけのコンソールでこのようgroupizationsからhas_many関係を通じてロール情報にアクセスしたい

:あなたのUserモデルで

2

これに対する最善のアプローチは、参加モデルで動作し、その後、Eをグループに/プロキシメソッドを委譲することです。G:その後

class User < ActiveRecord::Base 
    has_many :memberships, :include => :group, :dependent => :delete_all 
    has_many :groups, :through => :memberships 
end 

class Group < ActiveRecord::Base 
    has_many :memberships, :include => user, :dependent => :delete_all 
    has_many :users, :through => :memberships 
end 

class Membership < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :group 

    def group_name 
    group && group.name 
    end 

    def user_name 
    user && user.name 
    end 
end 

ビューでユーザーのグループを表示した場合:グループのユーザーのために、同様

<ul> 
<% @user.memberships.each do |membership| %> 
    <li><%= membership.group_name %> (<%= membership.role %>)</li> 
<% end %> 
</ul> 

は:

<ul> 
<% @group.memberships.each do |membership| %> 
    <li><%= membership.user_name %> (<%= membership.role %>)</li> 
<% end %> 
</ul> 

この方法は3つのしかクエリを取る - 1それぞれユーザー、グループ、メンバーシップのためのものです。

関連する問題