【问题标题】:Rails Ajax create a new instance of a model and add a checkbox for it to a formRails Ajax 创建模型的新实例并将其添加到表单中
【发布时间】:2015-11-10 16:20:33
【问题描述】:

我有一个呈现两个表单部分的视图:

匹配/new.html.erb:

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

matches/form 是一个新匹配的形式。在表单上,​​您可以将现有玩家添加到团队。 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 %>

在players/new中你可以创建新的Players:

玩家/_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

views/players/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>");

【问题讨论】:

  • 当你的create.js.erb 只包含$('#new_match').replaceWith("&lt;p&gt;Replaced&lt;/p&gt;"); 时发生了什么?
  • ActionView::Template::Error(缺少部分播放器/_matches,应用程序/_matches 与 {:locale=>[:en], :formats=>[:js, :html], :variants =>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}。搜索:* "/home/andrew/projects/foosball/app/views"):
  • 我询问了.replaceWith("&lt;p&gt;Replaced&lt;/p&gt;"); 您正在报告指定的部分。我猜那是给$("&lt;%= escape_javascript(render partial: 'matches') %&gt;"); 的。你可能想要这个:$('#new_match').html("&lt;%= escape_javascript(render partial: 'matches/form') %&gt;");.
  • 当使用渲染部分:'matches/form'时,不会出现新的复选框。页面刷新使其出现。
  • 在您的collection_check_boxes 方法调用中,players 是局部变量吗?您为players 分配了什么值?如果您将players 替换为Player.all,您可能会得到您期望的结果。

标签: ruby-on-rails ajax


【解决方案1】:

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

我在https://github.com/Yorkshireman/foosball/commit/2413eb576f96333acbb02f1bb05689ae1dc47d3e (temp_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') %>");
    

第二行对最终结果没有影响,所以可以去掉。

  1. PlayersController#create,我补充说:

    @match = Match.new(league: current_league)
    

添加新玩家成功更新复选框。如果这些更改对您不起作用,那么它们可能是您遇到的特定于浏览器的 JS 问题。

【讨论】:

  • 谢谢你,在你的帮助下我终于破解了! (稍作调整)。一些 Rails 魔法阻碍了。我要构建一个答案现在发布。
  • 我已经编辑了原始问题。回答跟随。
【解决方案2】:

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

感谢 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"

所以我用谷歌搜索了那个错误代码并看到了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,但如果有人能对此有所了解,那就太好了。

【讨论】:

  • 1.更改这些行的顺序应该对您的应用没有影响。它们不相互依赖。您只是设置传递给create 视图的实例变量。 2. 查看本 Rails 指南中第 3.4.4 节的最后一个示例:guides.rubyonrails.org/…render @player 呈现您的 players/_player 部分,并且您正在附加该部分。 3. 研究 jQuery 示例,看看 appendTo (api.jquery.com/appendTo) 发生了什么。
  • 该死,你说得对这些行的顺序。我需要检查 git 日志以找出真正使它起作用的原因。
猜你喜欢
  • 1970-01-01
  • 2018-11-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多