【问题标题】:Rails 5 and AJAX - can't do autocomplete and saving a nested formRails 5 和 AJAX - 无法自动完成和保存嵌套表单
【发布时间】:2017-07-21 05:33:48
【问题描述】:

有一种团队模型,其中有很多用户。用户与has_many :through 等团队模型相关联。 搜索用户时需要自动填充字段,选择用户时需要添加嵌套字段。

app/controllers/teams_controller.rb

class TeamsController < ApplicationController

  # GET /teams/new
  def new
    @team = Team.new #(parent_id: params[:parent_id])
  end

  # GET /teams/1/edit
  def edit
  end

  # POST /teams
  def create
    @team = Team.new(team_params)

    respond_to do |format|
      if @team.save
        format.html { redirect_to @team, success: t('.flash.success.message') }
      else
        format.html { render :new, danger: t('.flash.danger.message') }
      end
    end
  end

  # GET /teams/1/search_team_user
  def search_team_user
    @users = User.order(:first_name).where("first_name like ?", "%#{params[:term]}%")
    render json: @users.map { |u| { value: u.id, label: u.name } }
  end

  # GET /teams/1/new_team_user
  def new_team_user
    @team = Team.find(params[:id])
    @new_team_user = @team.team_users.build(user_id: params[:user_id])
  end

  private

    # Never trust parameters from the scary internet, only allow the white list through.
    def team_params
      params.require(:team).permit(
        :name,
        :parent_id,
        team_users_attributes: [:_destroy, :id, :user_id]
      )
    end
end

app/config/routes.rb

resources :teams do
  get :search_team_user, on: :member
  get :new_team_user, on: :member
end

app/views/teams/_form.html.erb

<%= form_for(@team) do |f| %>
  <div class='row'>
    <div class='<%= column_class %>'>
      <div class='form-group row'>
        <div class='<%= dynamic_small_column_class %>'>
          Team membership
        </div>
        <div class='<%= dynamic_large_column_class %>'>
          <div id='team-user-select' class='new-nested-group mb-3'>
            <%= text_field_tag 'search_team_users', nil, class: 'form-control autocomplete autocomplete-search new-nested-object', data: { autocomplete_object_id: true, autocomplete_source: search_team_user_team_path(@team), new_nested_object_path: new_team_user_team_path(@team) } %>
            <%= hidden_field_tag 'user_id', nil, class: 'autocomplete autocomplete-value new-nested-object' %>
          </div>
          <div id='team-users' class='nested-objects'>
            <%= render 'team_user_fields', f: f, team_users: @team_users, child_index: nil %>
          </div>
        </div>
      </div><!-- /.form-group.row -->
    </div><!-- /.col -->
  </div><!-- /.row -->
  <hr class='my-5'>
  <div class='row'>
    <div class='<%= column_class %>'>
      <div class='pull-right'>
        <%= cancel_link %>
        <%= save_link %>
      </div>
    </div><!-- /.col -->
  </div><!-- /.row -->
<% end %>

app/views/teams/new_team_user.js.erb

$('#team-users').append("<%= j(fields_for(@team) { |f| render('team_user_fields', f: f, team_users: @new_team_user, child_index: Time.now.to_i) }) %>");

app/assets/javascripts/nested_form.coffee

# # Autocomplete plagin
#
$.fn.customAutocomplete = ->
  @each (i, el) ->
    el = $(el)
    el.autocomplete
      minLength: 1
      source: el.data('autocomplete-source')
      focus: (event, ui) ->
        el.val ui.item.label
        false
      select: (event, ui) ->
        el.val ''
        el.next('.autocomplete.autocomplete-value').val ui.item.value

        url = el.data("new-nested-object-path")
        data = $('.new-nested-group :input, .new-nested-object').serialize()

        $.ajax
          url: url
          data: data
          dataType: 'script'
        false

# # Delete nested item
removeNestedObject = (element, objName) ->
  $("[name='"+objName+"[_destroy]']").val true
  $(element).closest('.removable-nested-object').remove()

$(document).on 'click', 'a.remove-nested-object', ->
  objName = $(this).data('object-name')
  removeNestedObject(this, objName)

# # On load
#
$(document).on 'turbolinks:load', ->

  $('a.add-nested-object').click (e) ->
    e.preventDefault()

    url = @href
    data = $('.new-nested-group :input, .new-nested-object').serialize()

    $.ajax
      url: url
      data: data
      dataType: 'script'

  $('.autocomplete.autocomplete-search').customAutocomplete()

此代码在转换到团队新页面时生成此错误:

显示 /Users/nikolaylipovtsev/Documents/Projects/inbox_task/app/views/teams/_form.html.erb 提出第 23 行的位置:

没有路线匹配 {:action=>"search_team_user", :controller=>"teams", :id=>#, :locale=>:ru} 缺少必填项 键:[:id]

需要改变什么?

【问题讨论】:

    标签: jquery ruby-on-rails ajax autocomplete


    【解决方案1】:

    以下路线表示需要具有有效id 的团队

    get :search_team_user, on: :member
    

    在新的团队页面中,@team 是使用 @team = Team.new 创建的,因此其 id 属性为零。这正是错误所说的

    没有路线匹配 {:action=>"search_team_user", :controller=>"teams", :id=>#, :locale=>:ru} 缺少必需的键:[:id]

    在TeamsController#search_team_user,我可以看到这个动作不需要团队就能正确运行。所以要解决这个问题,你可以改变你的路线到

    resources :teams do
      get :search_team_user, on: :collection
      get :new_team_user, on: :member
    end
    

    【讨论】:

    • 是的,但是团队 [:id] 需要 TeamsController#new_team_user。这是正确保存关联的需要。
    • @NikolayLipovtsev 看看路线,new_team_user 还在会员中。
    • 而这条路径new_team_user在新视图中,会报错&lt;%= text_field_tag 'search_team_users', nil, class: 'form-control autocomplete autocomplete-search new-nested-object', data: { autocomplete_object_id: true, autocomplete_source: search_team_user_team_path(@team), new_nested_object_path: new_team_user_team_path(@team) } %&gt;
    • @NikolayLipovtsev 如果业务逻辑规定新用户必须与团队相关联。在团队“创建”表单中显示创建新用户的链接是没有意义的,因为没有团队可以关联新用户。只在编辑团队时显示该链接不是更有意义吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多