2010-01-21 63 views
6

我有兩個使用has_and_belongs_to_many的多對多關係模型。像這樣:如何使用has_and_belongs_to_many將新模型與現有模型相關聯

class Competition < ActiveRecord::Base 
    has_and_belongs_to_many :teams 
    accepts_nested_attributes_for :teams 
end 

class Team < ActiveRecord::Base 
    has_and_belongs_to_many :competitions 
    accepts_nested_attributes_for :competitions 
end 

如果我們假設我已經在數據庫中創建一些比賽,當我創建一個新的團隊,我想用一個嵌套的形式向新的團隊與任何有關比賽相關聯。

在這一點上,我真的需要幫助(已經堅持了幾個小時!),我認爲我現有的代碼已經走錯了方向,但我會顯示它以防萬一:

class TeamsController < ApplicationController 
    def new 
    @team = Team.new 
    @competitions.all 
    @competitions.size.times {@team.competitions.build} 
    end 
    def create 
    @team = Team.new params[:team] 
    if @team.save 
     # .. usual if logic on save 
    end 
    end 
end 

而這個觀點......這是我真正被困住的地方,所以我不會同時發佈我的努力。我希望每個比賽都有一個複選框列表,以便用戶可以選擇哪些比賽是合適的,而不選中那些不合適的比賽。

我真的堅持了這一個,這樣欣賞在正確的方向指向任何可以提供:)

回答

4

連接模型一起的has_and_belongs_to_many方法已不支持新的has_many的...:通過方法。管理存儲在has_and_belongs_to_many關係中的數據是非常困難的,因爲沒有Rails提供的默認方法,但是:through方法是一流的模型,可以像這樣操作。

由於涉及到你的問題,你可能要解決這個問題是這樣的:

class Competition < ActiveRecord::Base 
    has_many :participating_teams 
    has_many :teams, 
    :through => :participating_teams, 
    :source => :team 
end 

class Team < ActiveRecord::Base 
    has_many :participating_teams 
    has_many :competitions, 
    :through => :participating_teams, 
    :source => :competition 
end 

class ParticipatingTeam < ActiveRecord::Base 
    belongs_to :competition 
    belongs_to :team 
end 

當談到創建團隊本身,您應該構建您的形式,讓你收到的參數之一是作爲數組發送。通常情況下,通過將所有複選框字段指定爲相同名稱來完成此操作,例如「競賽[]」,然後將每個複選框的值設置爲競賽的ID。然後,控制器會是這個樣子:

class TeamsController < ApplicationController 
    before_filter :build_team, :only => [ :new, :create ] 

    def new 
    @competitions = Competitions.all 
    end 

    def create 
    @team.save! 

    # .. usual if logic on save 
    rescue ActiveRecord::RecordInvalid 
    new 
    render(:action => 'new') 
    end 

protected 
    def build_team 
    # Set default empty hash if this is a new call, or a create call 
    # with missing params. 
    params[:team] ||= { } 

    # NOTE: HashWithIndifferentAccess requires keys to be deleted by String 
    # name not Symbol. 
    competition_ids = params[:team].delete('competitions') 

    @team = Team.new(params[:team]) 

    @team.competitions = Competition.find_all_by_id(competition_ids) 
    end 
end 

設置的勾選或者在您的複選框上市的每個元素用類似所做的狀態:

checked = @team.competitions.include?(competition) 

在哪裏「競爭」是一個正在迭代。

您可以輕鬆地在競賽列表中添加和刪除項目,或者簡單地重新分配整個列表,並且Rails將基於此列出新的關係。除了您將使用update_attributes而不是new外,您的更新方法與新方法看起來沒有什麼不同。

+2

謝謝你的回答(和apolgies需要幾天的迴應)。你的解決方案運行良好,儘管我花了一點時間來研究如何構建表單。 爲了其他人的利益,儘管團隊形式是使用form_for helper生成的,但對於比賽部分,我手動創建瞭如下複選框: <%= check_box_tag「team [competitions] []」,比賽。 id,@ team.competitions.include?(競賽),:id =>「team_competitions _#{competition.id}」%> – aaronrussell 2010-01-23 15:46:56

相關問題