Rails Ajax创建模型的新实例,并为表单添加一个复选框

时间:2015-11-10 16:20:34

标签: ruby-on-rails ajax

我有一个视图,呈现两个形式的部分:

匹配/ new.html.erb:

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

matches / form是新Match的表单。在表单上,​​您可以将现有玩家添加到团队中。 Players集合呈现为一组复选框。提交表单后,将使用其中选定的玩家创建团队:

匹配/ _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 %>

在玩家/新玩家中,您可以创建新的玩家:

播放器/ _new.html.erb:

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

所以我的想法是,我希望能够通过AJAX创建一个播放器(表格确实成功地完成了),然后将该播放器的复选框添加到视图中的播放器复选框集合中,而不是页面刷新。

我尝试了一些不同的东西(你会在create.js.erb文件中看到一些注释掉的东西)。我已经被困在这几天了,我用谷歌搜索了它。求救!

Github回购:https://github.com/Yorkshireman/foosball

控制器:

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

视图/播放器/ 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>");

2 个答案:

答案 0 :(得分:1)

我认为您的create_players分支的链接与您在此问题中发布的代码之间存在一些不一致。

我在https://github.com/Yorkshireman/foosball/commit/2413eb576f96333acbb02f1bb05689ae1dc47d3etemp_branch)结帐了您的代码,然后进行了以下更改:

  1. 我将@cat@dog替换为@player

  2. 我将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') %>");
    
  3. 第二行对最终结果没有影响,因此可以将其删除。

    1. PlayersController#create中,我补充道:

      @match = Match.new(league: current_league)
      
    2. 添加新播放器会成功更新复选框。如果这些更改对您不起作用,那么它们可能是您遇到的特定于浏览器的JS问题。

答案 1 :(得分:0)

好的,所以这是在任何重构之前,但它确实有效。

感谢sealocal,create.js现在显示为:

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

但遗憾的是,我并不完全明白这里发生了什么;我认为appendTo实际上会在浏览器中呈现播放器复选框,但似乎整个部分都在下一行重新渲染?为什么是这样? appendTo到底做了什么?

这是奇怪的事情 - 像这样的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

我收到了错误:

 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"

所以我用Google搜索了错误代码并看到了this(不是答案,但是海报上的说法,在第3行:“它正在请求与模型同名的视图。”)。所以我认为这必须是一些Rails魔术,从#create方法推断出视图。所以......(鼓声)...

我尝试将@match行转移到@player行和BOOM之上!它奏效了!:

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

但是,如果我是诚实的,我不会完全确定为什么这样做。现在,我把它归结为Rails,但是如果有人能够对它有更多的了解,那就太棒了。