所以我必须遵循模特。
class Team < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :players
accepts_nested_attributes_for :players
end
class Player < ActiveRecord::Base
has_many :statistics
has_and_belongs_to_many :teams
end
我希望建立一个拥有玩家的团队,这些将由用户选择。我可以通过以下方式在控制台中完美地完成此操作。
@user = User.find(10)
@team = @user.build_team(name: "MyTeam", points: 0)
#<Team team_id: nil, name: "MyTeam", points: 0, user_id: 10>
@team.players.build(name: "Messi")
#<Player player_id: nil, name: "Messi", role: nil>
@team.save
然而,由于强大的参数,我真的在努力传递参数。这是我的观点
<%= form_for :team do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.fields_for :players do |players| %>
<%= players.label :player_name %>
<%= players.text_field :name %>
<% end %>
<div><%= f.submit "Create Team" %></div>
<% end %>
我想使用团队参数和使用播放器参数的玩家来构建团队,但是我无法弄清楚如何在控制器中使用它。
class TeamController < ApplicationController
before_action :authenticate_user!
def new
end
def create
@user = User.find(current_user.id)
@team = @user.build_team(team_params) #Just the team paramaters
@team = @team.players.build(player_params)# I want just the player params
@team.save
end
private
# I can add the player param as nested i.e. .permit(:name, :players => [:name])
# but then build_team complains about receiving an array.
def team_params
params.require(:team).permit(:name)
end
end
欢迎任何解决方案,以及任何改进。
编辑 - 添加模式
create_table "players", primary_key: "player_id", force: true do |t|
t.string "name", limit: 50, null: false
t.string "role", limit: 30, null: false
end
create_table "players_teams", id: false, force: true do |t|
t.integer "player_id", null: false
t.integer "team_id", null: false
end
# players_teams is a Composite Primary Key, as instructed in the guides;
# also essential for targeting.
create_table "teams", primary_key: "team_id", force: true do |t|
t.string "name", limit: 200, null: false
t.integer "points", default: 0, null: false
t.integer "user_id", null: false
end
编辑2
由于尚未得到回答,我将对我正在尝试的内容添加更多解释。
用户有一个团队,我可以建立团队,并且由于ActiveRecord也建立了关系。然后用户团队有很多玩家和玩家有很多团队,当我尝试建立这种关系时,玩家表永远不会改变,没有创建任何关系。
我觉得我应该再次强调以下功能在rails控制台中完美运行
@user = User.find(10)
@team = @user.build_team(name: "MyTeam", points: 0)
#<Team team_id: nil, name: "MyTeam", points: 0, user_id: 10>
@team.players.build(name: "Messi")
#<Player player_id: nil, name: "Messi", role: nil>
@team.save
团队设置为接受嵌套参数,所以我认为这样可行。
@team = @user.build_team(team_params)
def team_params
params.require(:team).permit(:name, players_attributes: [:name, :role])
end
我认为这应该建立玩家模型并创建关系,但是没有玩家插入任何玩家并且没有建立任何关系。
答案 0 :(得分:7)
首先在TeamsController
中进行一些更改,如下所示:
class TeamController < ApplicationController
before_action :authenticate_user!
def new
## Set "@team" and build "players"
@team = current_user.build_team
@team.players.build
end
def create
@team = current_user.build_team(team_params)
if @team.save
## Redirect to teams show page
redirect_to @team, notice: 'Team was successfully created.'
else
## In case of any error while saving the record, renders the new page again
render action: 'new'
end
end
private
# I can add the player param as nested i.e. .permit(:name, :players => [:name])
# but then build_team complains about receiving an array.
def team_params
## Permit players_attributes
params.require(:team).permit(:name, players_attributes: [:id, :name])
end
end
在此之后,更新视图如下:
<%# Changed "form_for :team" to "form_for @team" %>
<%= form_for @team do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.fields_for :players do |player| %> <%# Changed "|players|" to "|player|" %>
<%= player.label :name %> <%# Changed "player_name" to "name" and "players" to "player" %>
<%= player.text_field :name %> <%# Changed "players" to "player" %>
<% end %>
<div><%= f.submit "Create Team" %></div>
<% end %>
在@team
操作中设置实例变量new
,并为@team
构建播放器。
在视图代码中使用@team
实例变量作为form_for
的参数。
我还建议在create
操作中进行一些调整,以便了解团队是否已保存。
并修复了team_params
方法以允许players
的嵌套属性。
<强>更新强>
使用@team
作为form_for
方法的参数是面向资源的样式,也是首选的方式。
阅读关于usage of form_for的这个非常好的描述,以获得更好的主意。
您仍然可以在使用:team
时实现所需的代码,但其不是首选方式。
使用:team
的示例:
<%= form_for :team do |f| %>
<%# ... %>
<%= f.fields_for :players, f.object.players.build do |player| %> <%# build the players for the team %>
<%# ... %>
<% end %>
<%# ... f.submit "Create Team" %>
<% end %>
在您的情况下, fields_for
会迭代属于特定团队(@team.players
)的玩家(@team
)。如果没有玩家,那么你将不会在表单中看到任何玩家的字段,这就是为什么你建立玩家所以你至少得到一些空白字段供玩家输入,这就是为什么当你使用accepts_nested_attributes_for
时构建嵌套属性。您可以在控制器级别(如上面建议的代码所示)或在表单内构建它们。
“在表单内”的示例:
<%= form_for @team do |f| %>
<%# ... %>
<%= f.fields_for :players, @team.players.build do |player| %> <%# build the players for @team %>
<%# ... %>
<% end %>
<%# ... f.submit "Create Team" %>
<% end %>
答案 1 :(得分:1)
通常你只需要立即执行嵌套属性,这将通过嵌套属性创建玩家,例如。
def create
@user = User.find(current_user.id)
@team = @user.build_team(team_params)
@team.save
end
def team_params
params.require(:team).permit(:name, :players => [:name])
end
如果你迫切希望将它们分开,你应该可以做类似
的事情def player_params
params.require(:team).permit(:name, :players => [:name])[:team][:players]
end
即。你将不得不过滤出玩家参数
答案 2 :(得分:1)
由于我本周末经历了同样的问题,我强烈建议使用nested_form。
您可以在此处找到所有实施细节:https://github.com/ryanb/nested_form
答案 3 :(得分:0)
你与自己拥有的非常接近。
只需将:id字段添加到player_attributes params,它就适合您。
def team_params
params.require(:team).permit(:name, players_attributes: [:id, :name, :role])
end
您可能需要查看cocoon gem。它使得处理嵌套表单和允许用户使用JS添加/删除更容易。
如果您还想允许销毁,请在播放器上添加字段_destroy的复选框,并在players_attributes中添加该键。同时更新模型以允许销毁。
型号:
class Team < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :players
accepts_nested_attributes_for :players, allow_destroy: true
end
控制器:
def team_params
params.require(:team).permit(:name, players_attributes: [:id, :_destroy, :name, :role])
end
查看:
<%= f.fields_for :players do |player| %> <%# Changed "|players|" to "|player|" %>
<%= player.label :name %> <%# Changed "player_name" to "name" and "players" to "player" %>
<%= player.text_field :name %> <%# Changed "players" to "player" %>
<%= player.check_box :_destroy %> Delete
<% end %>