简体   繁体   English

Rails Ajax创建模型的新实例,并将其复选框添加到表单

[英]Rails Ajax create a new instance of a model and add a checkbox for it to a form

I have a view that renders two form partials: 我有一个呈现两个表单部分的视图:

matches/new.html.erb: matchs / new.html.erb:

<%= render 'players/new' %>
<%= render 'matches/form' %>

matches/form is a form for a new Match. 比赛/表格是新比赛的表格。 On the form you can add existing Players to Teams. 在表单上,​​您可以将现有玩家添加到团队中。 The Players collection is rendered as a collection of checkboxes. Players集合呈现为复选框的集合。 When the form is submitted, the Teams get created with those selected Players inside them: 提交表单后,将在团队内部创建选定的玩家:

matches/_form.html.erb: matchs / _form.html.erb:

<%= form_for @match do |f| %>
    <%= f.fields_for :team_1 do |team_1_form| %>
        <%= team_1_form.label "Team 1" %><br>
        <%= team_1_form.collection_check_boxes :player_ids, Player.all, :id, :name, include_hidden: false %>
    <% end %>
    <br>
    <%= f.fields_for :team_2 do |team_2_form| %>
        <%= team_2_form.label "Team 2" %><br>
        <%= team_2_form.collection_check_boxes :player_ids, Player.all, :id, :name, include_hidden: false %>
    <% end %>
    <br>
    <%= f.submit "Start Match" %>
<% end %>

In players/new you can create new Players: 在玩家/新玩家中,您可以创建新玩家:

players/_new.html.erb: players / _new.html.erb:

<%= form_for @player, remote: true do |f| %>
    <%= f.text_field :name %>
    <%= f.submit 'Create Player' %>
<% end %>

So the idea is, I want to be able to create a Player (which the form does do successfully, by the way) via AJAX and for that Player's checkbox to be added to the Players' checkbox collection in the view without a page refresh. 因此,我的想法是,我希望能够通过AJAX创建一个Player(顺便说一句,表单确实成功完成了此工作),并且该Player的复选框可以添加到视图中的Player的复选框集合中,而无需刷新页面。

I've tried a few different things (you'll see a few commented-out things in the create.js.erb file). 我尝试了一些其他操作(您会在create.js.erb文件中看到一些注释掉的内容)。 I've been stuck on this for days and I've googled the hell out of it. 我已经坚持了好几天,并且用谷歌搜索了它。 Help please! 请帮助!

Github repo: https://github.com/Yorkshireman/foosball Github仓库: https : //github.com/Yorkshireman/foosball

Controllers: 控制器:

class PlayersController < ApplicationController
    def create
        @player = Player.create(name: params[:player][:name], league: current_league)
        @match = Match.new
        current_league.players << @player
        respond_to do |format|
            format.js   {}
        end
    end
end

class MatchesController < ApplicationController
    def new
        @player = Player.new
        @players = Player.all
        @match = Match.new
    end

    def create
        @match = Match.new(league: current_league)

        if team_1_player_ids && team_2_player_ids
            teams = BuildTeams.call team_1_player_ids, team_2_player_ids, current_league
            InsertTeamsIntoMatch.call teams, @match
            @match.save
            render nothing: true
        else
            flash[:alert] = "Please select players for both teams"
            render :new
        end
    end


    private

    def team_1_player_ids
        params[:match] && params[:match][:team_1] && params[:match][:team_1][:player_ids]
    end

    def team_2_player_ids
        params[:match] && params[:match][:team_2] && params[:match][:team_2][:player_ids]
    end
end

views/players/create.js.erb: 视图/播放器/create.js.erb:

// $("<%= escape_javascript(render partial: 'matches') %>");
// $('#new_match_div').html("<%= escape_javascript(render 'matches/new') %>");
$('#new_match').html("<%= escape_javascript(render 'matches/form') %>");

// $('#new_match').replaceWith("<p>Replaced</p>");

I think there are some inconsistencies between the link to your create_players branch and the code that you posted in this question. 我认为您create_players分支的链接与您在此问题中发布的代码之间存在一些不一致之处。

I checkout out your code at https://github.com/Yorkshireman/foosball/commit/2413eb576f96333acbb02f1bb05689ae1dc47d3e ( temp_branch ), then made the following changes: 我签了你的代码在https://github.com/Yorkshireman/foosball/commit/2413eb576f96333acbb02f1bb05689ae1dc47d3etemp_branch ),然后进行了如下修改:

  1. I replaced both @cat and @dog with @player . 我换过两个@cat@dog@player

  2. I changed the contents of app/views/player/create.js.erb to read exactly as this: 我将app/views/player/create.js.erb的内容更改为完全如下所示:

     $("<%= escape_javascript(render @player) %>").appendTo("#new_match"); $('#new_match').html("<p>Replaced</p>"); $('#new_match').html("<%= escape_javascript(render partial: 'matches/form') %>"); 

The second line has no effect on the end result, so it can be removed. 第二行对最终结果没有影响,因此可以将其删除。

  1. In the PlayersController#create , I added: PlayersController#create ,我添加了:

     @match = Match.new(league: current_league) 

Adding a new player successfully updates the checkboxes. 添加新播放器会成功更新复选框。 If those changes do not work for you, then their might a be browser-specific JS problem that you're encountering. 如果这些更改对您不起作用,那么它们可能是您遇到的特定于浏览器的JS问题。

Ok, so this is before any refactoring, but it works. 好的,所以这是任何重构之前的事情,但是可以。

Thanks to sealocal, the create.js now reads: 感谢sealocal,create.js现在显示为:

$("<%= escape_javascript(render @player) %>").appendTo("#new_match");
$('#new_match').html("<%= escape_javascript(render partial: 'matches/form') %>");

But unfortunately, I don't fully understand what is going on here; 但是不幸的是,我不完全了解这里发生了什么。 I thought appendTo would actually render the player checkbox in the browser, but it seems the entire partial has be re-rendered on the next line? 我以为appendTo实际上会在浏览器中渲染播放器复选框,但似乎整个部分都已在下一行重新渲染了? Why is this? 为什么是这样? What does appendTo do exactly? appendTo到底做什么?

Here's the weird thing - with the PlayersController like this: 这是很奇怪的事情-使用PlayersController是这样的:

class PlayersController < ApplicationController
    def create
        @player = Player.create(name: params[:player][:name], league: current_league)
        @match = Match.new(league: current_league)
        current_league.players << @player
        respond_to do |format|
            format.js   {}
        end
    end
end

I was getting the error: 我收到错误:

 Rendered players/create.js.erb (33.7ms)
Completed 500 Internal Server Error in 314ms (ActiveRecord: 19.8ms)

ActionView::Template::Error (Missing partial players/_matches, application/_matches with {:locale=>[:en], :formats=>[:js, :html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in:
  * "/home/andrew/projects/foosball/app/views"

So I googled that error code and saw this (not the answer, but where the poster says, on line 3: "it is requesting a view with the same name as the model."). 因此,我搜索了该错误代码,并看到了这个错误代码(不是答案,而是张贴者在第3行上说的:“它正在请求与模型同名的视图。”)。 So I figured this must be some Rails magic, inferring the view from the #create method. 因此,我认为这一定是Rails的魔力,它可以从#create方法推断出视图。 SO... (drum roll)... 等等...

I tried shifting the @match line to above the @player line and BOOM! 我尝试将@match行移到@player行和BOOM上方! It worked!: 有效!:

class PlayersController < ApplicationController
    def create
        @match = Match.new(league: current_league)
        @player = Player.create(name: params[:player][:name], league: current_league)
        current_league.players << @player
        respond_to do |format|
            format.js   {}
        end
    end
end

If I'm honest, though, I'm not entirely sure why this works. 不过,如果我说实话,我不完全确定为什么会这样。 For now, I have put it down to Rails, but if someone could shed some more light on it, that would be great. 现在,我将其归结为Rails,但是如果有人可以对其进行更多说明,那就太好了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM