Activerecord协会问题:获得has_many:通过工作

时间:2008-10-13 20:00:45

标签: ruby-on-rails ruby activerecord

我正在Ruby on Rails中构建一个应用程序,我将包括我的3个模型(及其迁移脚本),以显示我正在尝试做什么,以及什么不起作用。这是纲要:我的应用程序中的用户属于团队,每个团队可以有多个教练。我希望能够提取适用于用户的教练列表。

例如,用户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 ::错误:#42S22Unknown列'teams.user_id'在'where子句'中:SELECT coaches。* FROM coaches INNER JOIN团队ON coaches.team_id = teams.id WHERE(( teams。user_id = 1))

我在miss:through子句中遗漏了什么?我的设计完全关闭了吗?有人能指出我正确的方向吗?

5 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分: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}'

答案 2 :(得分:1)

我不认为ActiveRecord可以处理has_many关系中的两步连接。为了实现这一目标,您必须将用户加入team_users,以及团队和教练。 through选项只允许一次额外的连接。

相反,你必须使用:finder_sql选项并自己写出完整的join子句。这不是世界上最漂亮的东西,但当你尝试做一些与众不同的事情时,它就是ActiveRecord的用法。

答案 3 :(得分:1)

您可以删除用户中的“has_many:coaches,:through =&gt;:teams”行。然后在你的用户模型中手写一个coach方法,如下所示:

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

答案 4 :(得分: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

我想过一下子就这么做了,但我喜欢从用户对象中返回一个coach对象数组的能力。如果有更好的方法,我很有兴趣看到改进的代码。