在Rails 3.2.2中使用simple_forms gem,我已经构建了一个表单来在嵌套模型中创建对象(在railscasts.com上再次向Ryan Bates致敬)但我正在努力掌握has_many通过关系的复杂性无需向我的游戏控制器的create方法添加额外的代码。
我在我的游戏模型中使用accepts_nested_attributes_for:参与者,希望能够批量分配2个必需的参与者对象。
我有三个课程:游戏,团队和参与者
参与者存在,因此团队可以被视为游戏中的主队或客队。
目前,我正在使用表单中的select_tag来创建一些psuedo参数,然后我用它来保存新的@game对象后在控制器的create方法中创建参与者我正在创建一个@game 。主队和客队的参赛者。这一切都有效但有点过于繁重,如果我想要创建一个游戏锦标赛而不需要编写更多的控制器代码,则无法扩展。
所以现在我在新方法中构建了2次参与者,并尝试在不添加额外代码的情况下创建和更新工作,并在create方法中删除创建@ games.participants。
好的......问题......
builder.input:team_id,:collection => Team.all
这会将对象id放在选择器中,我希望Team.full_name在当前生成 select_tag“home”,options_from_collection_for_select(Team.all,:id,:full_name)和id为be 推进了team_id param。我正在努力寻找合适的simple_forms文档和 透过宝石来源看到了我的头痛(我不够好解码它)
我需要区分在新Game对象中创建的两个参与者。该 simple_form f.simple_fields_for:参与者do | builder |不允许我这样做 :participant.first或:participant.last。我想创建一个隐藏字段设置:home_team 对于第一个参与者来说是真的。
如果我能让这两件作品发挥作用,那么我认为我的解决方案可行。任何帮助或线索一如既往地非常受欢迎。
游戏模型:
class Game < ActiveRecord::Base
belongs_to :venue
belongs_to :game_type
has_and_belongs_to_many :tournaments
has_many :participants, :dependent => :destroy
has_many :teams, :through => :participants
validates :kickoff, :venue_id, :presence => true
accepts_nested_attributes_for :participants,
:reject_if => lambda {|a| a[:game_id].blank? },
:allow_destroy => :true
def home_team
self.teams.joins(:participants).where("participants.home_team = ?", true).first
end
def away_team
self.teams.joins(:participants).where("participants.home_team = ?", false).first
end
end
参与者模型:
class Participant < ActiveRecord::Base
belongs_to :game
belongs_to :team
end
团队模型:
class Team < ActiveRecord::Base
has_many :participants, :dependent => :destroy
has_many :games, :through => :participants
validates :full_name, :presence => true
validates :short_name, :presence => true, :length => { :within => 1..5 }
end
游戏控制器(新建和创建方法)
class GamesController < ApplicationController
def new
@game = Game.new
### This section is not currently implemented
# 2.times { @game.participants.build }
### End of unimplemented section
respond_to do |format|
format.html # new.html.erb
end
end
def create
@game = Game.new(params[:game])
respond_to do |format|
if @game.save
@game.participants.create(:team_id => params[:home], :home_team => true)
@game.participants.create(:team_id => params[:away], :home_team => false)
format.html { redirect_to games_path, notice: 'Game was successfully created.' }
else
format.html { render action: "new" }
end
end
end
游戏视图表单部分(实际上有另一部分,但为了便于阅读而包括在内)
<%= simple_form_for(@game) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= label_tag "home", "Home Team"%>
<%= select_tag "home", options_from_collection_for_select(Team.all, :id, :full_name)%>
<!-- This section is not working properly -->
<!-- <%=# f.simple_fields_for :participants do |builder| %> -->
<!-- <%=# builder.input :team_id, :collection => Team.all, :selected => :full_name %> -->
<!-- <%# end %> -->
<!-- End of not working properly section -->
<%= f.input :home_goals, :input_html => {:maxlength => 5, :size => 5 }%>
<%= f.input :away_goals, :input_html => {:maxlength => 5, :size => 5 }%>
<%= select_tag "away", options_from_collection_for_select(Team.all, :id, :full_name)%>
<%= label_tag "away", "Away Team"%>
<%= f.input :kickoff %>
<%= f.input :completed %>
<%= f.input :game_type_id %>
<%= f.input :venue_id ,:collection => Venue.all, prompt: 'Choose the venue'%>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
答案 0 :(得分:3)
好的......如果有人感兴趣我解决了以下两个问题:
使用类上的collect功能而不是任何simple_form助手,因此Games View Form Partial对收集行进行了以下更改:
<%= builder.input :team_id, :collection => Team.all.collect{ |t| [t.full_name, t.id ]}%>
我使用计数比较来设置可靠的注意隐藏字段的值。这不是非常对象代码,但意味着代码使用simple_form帮助程序,控制器只使用.save(在create中)和update_attributes(在更新中),而不需要任何进一步的代码。非常好。还略微修改了accepts_nested_attributes_for以查找空白的team_id而不是game_id(永远不会是空白!)。所以代码现在看起来如下......
游戏模型:
class Game < ActiveRecord::Base
belongs_to :venue
belongs_to :game_type
has_and_belongs_to_many :tournaments
has_many :participants, :dependent => :destroy
has_many :teams, :through => :participants
validates :kickoff, :venue_id, :presence => true
accepts_nested_attributes_for :participants,
:reject_if => lambda {|a| a[:team_id].blank? },
:allow_destroy => :true
def home_team
self.teams.joins(:participants).where("participants.home_team = ?", true).first
end
def away_team
self.teams.joins(:participants).where("participants.home_team = ?", false).first
end
end
游戏控制器(新建和创建方法)
class GamesController < ApplicationController
def new
@game = Game.new
2.times { @game.participants.build }
respond_to do |format|
format.html # new.html.erb
end
end
def create
@game = Game.new(params[:game])
respond_to do |format|
if @game.save
format.html { redirect_to games_path, notice: 'Game was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
游戏视图表单部分(实际上有另一部分,但为了便于阅读而包括在内)
<%= simple_form_for(@game) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<% count = 0 %>
<%= f.simple_fields_for :participants do |builder| %>
<% if count == 0 %>
<% value = true %>
<% count += 1 %>
<% else %>
<% value = false%>
<% end %>
<%= builder.input :home_team, :as => :hidden, :input_html => {:value => value} %>
<%= builder.input :team_id, :collection => Team.all.collect{ |t| [t.full_name, t.id ]}%>
<% end %>
<%= f.input :home_goals, :input_html => {:maxlength => 5, :size => 5 }%>
<%= f.input :away_goals, :input_html => {:maxlength => 5, :size => 5 }%>
<%= f.input :kickoff %>
<%= f.input :completed %>
<%= f.input :game_type_id %>
<%= f.input :venue_id ,:collection => Venue.all, prompt: 'Choose the venue'%>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
希望这对某人有用。我认为这是一个很好的解决方案,但如果有人提出改进视图逻辑的建议,我会很感兴趣。
此致
彼得