创建一个方法以在Rails 3.1中向表中添加新记录

时间:2012-02-02 06:42:28

标签: ruby-on-rails ruby-on-rails-3.1

我是Rails的新手。我有三个牌桌球员,名单和阵容。我有模型条目来创建玩家所属的关系 - 名单和阵容,名单上有很多玩家,阵容有很多玩家。

我遇到的问题是当我创建名单时,我有一个roster_name属性,我可以添加一个单独的玩家。我想在同一个阵容中添加更多玩家,但我正在努力解决如何将新玩家添加到名单中的问题。默认的新视图调用_form partial,它希望我创建一个全新的名单,这将允许我再次添加一个用户。

将新玩家添加到现有名单的轨道方式是什么?请帮我理解我需要的组件。我是否需要一个可以调用的新部分来添加新玩家?我是否必须创建新方法或控制器?我假设是我需要一种方法来引用现有的名单,同时能够添加新的player_id。任何帮助都会很棒。

这是我的模型/控制器和视图

My model roster.rb
class Roster < ActiveRecord::Base
    has_many :players

    accepts_nested_attributes_for  :players, :allow_destroy => true
end
My model player.rb
class Player < ActiveRecord::Base
    belongs_to :roster
end
My controller rosters_controller.rb
def new
    @roster = Roster.new
    @players = Player.all
End

My roster view
<%= form_for(@roster) do |f| %>                                   
  <% if @roster.errors.any? %>                                    
    <div id="error_explanation">                                  
      <h2><%= pluralize(@roster.errors.count, "error") %> prohibited this roster from being saved:</h2>

      <ul>
      <% @roster.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>                           
      <% end %>                                       
      </ul>                                           
    </div>                                            
  <% end %>                                           

  <div class="field">
    <%= f.label :player_id %><br />
    <%= f.text_field :player_id %>
  <%= collection_select("roster", "player_id", @players, "id", "gname") %>
  </div>
  <div class="field">
    <%= f.label :player_id %><br />
    <%= f.text_field :player_id %>
  <%= collection_select("roster", "player_id", @players, "id", "gname") %>

  </div>

  <div class="actions">
    <%= f.submit %>
  </div>

1 个答案:

答案 0 :(得分:0)

由于它是多对多关联,has_many :through关联通常用于与另一个模型建立多对多连接。该关联表明通过继续第三模型,声明模型可以与另一模型的零个或多个实例匹配。现在关联声明可能如下所示:

class Roster < ActiveRecord::Base
  has_many :roster_players
  has_many :players, :through => :roster_players
end

class RosterPlayer < ActiveRecord::Base
  belongs_to :roster
  belongs_to :player
end

class Player < ActiveRecord::Base
  has_many :roster_players
  has_many :roster, :through => :roster_players
end

第1步: 生成关联模型。

$> rails g model roster_player roster:references player:references
$> rake db:migrate

第2步: 您需要的是接受嵌套属性的方法。完成此rails cast并阅读nested_attributes。 rails cast的代码形式已被Ryan Bates提取为宝石,非常有用。

更新你的gemfile以要求这个宝石

gem 'nested_form'
$> bundle install

接下来运行生成器以创建JavaScript文件。这将自动检测您是否使用jQuery或Prototype。

rails g nested_form:install

运行生成器将添加一个文件nested_form.js,该文件应该包含在jQuery或Prototype框架之后。

<%= javascript_include_tag :defaults, "nested_form" %>

让我们将嵌套属性提取到名为_roster_player_fields.html.erb

的部分中
<div class="field">
  <%= f.label :player_id, "Player" %>
  <%= f.select :player_id, Player.all.collect { |p| [ p.name, p.id ] }, { :include_blank => true } %>
</div>

我们在这里要做的是为表单中的每个名册palyers添加字段。我们可以使用fields_for方法来管理表单中的关联字段,将其传递给关联模型的名称,然后遍历所有关联的播放器记录,并为每个记录创建表单构建器。构建器将为每个玩家渲染部分内容。

<%= form_for(@roster) do |f| %>                                   
  <% if @roster.errors.any? %>                                    
    <div id="error_explanation">                                  
      <h2><%= pluralize(@roster.errors.count, "error") %> prohibited this roster from being saved:</h2>

      <ul>
      <% @roster.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>                           
      <% end %>                                       
      </ul>                                           
    </div>                                            
  <% end %>                                           

  <% f.fields_for :roster_players do |builder| %>
    <%= render 'roster_player_fields', :f => builder %>
  <% end %>
  <%= link_to_add_fields "[+] Add Player", f, :roster_players %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

当渲染此表单时,它将看起来像以前一样。这是因为新名单中没有任何与之相关的玩家,因此不会显示任何玩家字段。最终我们希望在表单上有一个“添加播放器”链接,但我们可以在RosterController的新操作中创建一个roster_player,并显示其字段。

def new
  @roster = Roster.new
  @roster.roster_players.build
End

默认情况下,嵌套属性更新已关闭,您可以使用#accepts_nested_attributes_for类方法启用它。启用嵌套属性时,将在模型上定义属性编写器。这应该有效并希望它有所帮助。