2008-10-13 72 views
4

我正在Ruby on Rails中构建一个应用程序,并且我包含了我的三个模型(以及它们的迁移脚本)以显示我正在尝试执行的操作,以及什么不工作。下面是简介:我的应用程序中有属于团队的用户,每个团队可以有多个教练。我希望能够拉出适用于用户的教练列表。Activerecord关联问题:正在获取has_many:通过工作

例如,用户A可以属于团队T1和T2。 T1和T2队可以有四个不同的教练,每个教练都有一个共同的教练。我希望能够通过简单地说:

u = User.find(1) 
coaches = u.coaches 

以下是我的迁移脚本以及我的模型中的关联。我在设计中做错了什么吗?我的协会是否正确?

class CreateUsers < ActiveRecord::Migration 
    def self.up 
    create_table :users do |t| 
     t.column :login, :string, :default => nil 
     t.column :firstname, :string, :default => nil 
     t.column :lastname, :string, :default => nil 
     t.column :password, :string, :default => nil 
     t.column :security_token, :string, :default => nil 
     t.column :token_expires, :datetime, :default => nil 
     t.column :legacy_password, :string, :default => nil 
    end 
    end 

    def self.down 
    drop_table :users 
    end 
end 

class CreateTeams < ActiveRecord::Migration 
    def self.up 
    create_table :teams do |t| 
     t.column :name, :string 
    end 
    end 

    def self.down 
    drop_table :teams 
    end 
end 

class TeamsUsers < ActiveRecord::Migration 
    def self.up 
    create_table :teams_users, :id => false do |t| 
     t.column :team_id, :integer 
     t.column :user_id, :integer 
     t.column :joined_date, :datetime 
    end 
    end 

    def self.down 
    drop_table :teams_users 
    end 
end 

下面是模型(而不是整个文件):

class User < ActiveRecord::Base 

    has_and_belongs_to_many :teams 
    has_many :coaches, :through => :teams 

class Team < ActiveRecord::Base 
    has_many :coaches 
    has_and_belongs_to_many :users 

class Coach < ActiveRecord::Base 
    belongs_to :teams 
end 

这是当我尝试拉教练会发生什么:

u = User.find(1) 
=> #<User id: 1, firstname: "Dan", lastname: "Wolchonok"> 
>> u.coaches 
ActiveRecord::StatementInvalid: Mysql::Error: #42S22Unknown column 'teams.user_id' in 'where clause': SELECT `coaches`.* FROM `coaches` INNER JOIN teams ON coaches.team_id = teams.id WHERE ((`teams`.user_id = 1)) 

下面是SQL的错误:

Mysql ::错误:#42S22未知列'where子句'中的列'teams.user_id':SELECT coaches。* FRO (teams .user_id = 1)

我在我的:through子句中缺少一些东西吗?我的设计完全关闭了吗?有人能指引我朝着正确的方向吗?

回答

4

你不能做一个has_many:连续两次。它会告诉你它是一个无效的关联。如果你不想像上面那样添加finder_sql,你可以添加一个模拟你想要做的事情的方法。

def coaches 
    self.teams.collect do |team| 
     team.coaches 
    end.flatten.uniq 
    end 
1

我不认为ActiveRecord可以处理has_many关系中的2步连接。为了实现这个目标,你必须将用户和team_users加入到教练队伍中。直通选项只允许一个额外的连接。

相反,您必须使用:finder_sql选项并自己写出完整的连接子句。不是世界上最漂亮的东西,但是当你尝试做一些不寻常的事情时,这就是ActiveRecord的方式。

2

它更多的是多对多甚至更多的关系。我只是写了一些sql:

has_many :coaches, :finder_sql => 'SELECT * from coaches, teams_users WHERE 
       coaches.team_id=teams_users.team_id 
       AND teams_users.user_id=#{id}' 
1

你可以掉落“的has_many:教练:通过=>:团队”的用户线&然后在User模型手工编写的教练方法,像这样:

def coaches 
    ret = [] 
    teams.each do |t| 
    t.coaches.each do |c| 
     ret << c 
    end 
    end 
    ret.uniq 
end 
0

虽然我喜欢编写SQL,我不认为这是这种情况下的理想解决方案。这是我结束了在用户模式做:

def coaches 
    self.teams.collect do |team| 
     team.coaches 
    end.flatten.uniq 
    end 

    def canCoach(coachee) 
    u = User.find(coachee) 

    coaches = u.coaches 
    c = [] 
    coaches.collect do |coach| 
     c.push(coach.user_id) 
    end 

    return c.include?(self.id) 
    end 

我想过只是在做这一切一举,但我喜欢回到教练数组从用户对象中物体的能力。如果有更好的方法去做,我对看到改进的代码非常感兴趣。

+0

确保'flati'后使用'uniq',这样您就不会得到重复的教练。 – flicken 2008-10-14 14:17:57

相关问题