【问题标题】:Rails 4: AJAX contact form nested in another class's viewRails 4:嵌套在另一个类视图中的 AJAX 联系表单
【发布时间】:2017-01-26 14:16:13
【问题描述】:

我的应用有 Programmes,我希望用户能够通过 AJAX 表单提交 InfoRequests。 (在后台,这将触发向程序协调员发送包含表单输入的电子邮件。) Programmes 有页面(通过他们的show 操作呈现),这就是我想包含InfoRequest 的表单的地方。一旦发送请求,我希望用户看到积极的反馈,并且表单输入应该变成只读的,这样用户仍然可以看到他/她提交的内容,但不能直接再次提交。 我努力使 AJAX 工作,我不知道出了什么问题。我到达"InfoRequest not delivered" 行(见下文),这是预期的,因为我无法在我的开发环境中发送邮件。但是 AJAX 回调特别不会触发,所以我在表单中没有看到任何反应(也没有我在代码中放入的 window.alert 调用,除了 "init_info_request")。

这是我目前所拥有的 - 感谢任何帮助。我很乐意重新组织东西,只要它能让事情变得更精简和简单。


programmes_controller.rb

class ProgrammesController < ApplicationController
  def show
    @programme = Programme.friendly.find(params[:id])
    @info_request = InfoRequest.new(:programme => @programme)

    ...
  end
end

info_request.rb

class InfoRequest < MailForm::Base

  attribute :first_name,          :validate => true
  attribute :last_name,           :validate => true

  attribute :programme

  ...

end

info_requests_controller.rb

class InfoRequestsController < ApplicationController
  def new
    @info_request = InfoRequest.new
  end

  def create
    puts "**********> InfoRequest#create"

    @info_request = InfoRequest.new(params[:info_request])

    @info_request.programme = Programme.friendly.find(params[:info_request][:programme_id])

    @programme = @info_request.programme
    @coordinator = @info_request.programme.coordinator

    @info_request.request = request

    if @info_request.deliver
      puts "**********> InfoRequest delivered"
    else
      puts "**********> InfoRequest not delivered"
    end
    end
  end
end

programmes/show.html.erb

...
<%= render partial: 'info_requests/new' %>
...

info_requests/new.html

<%= render 'info_requests/new' %>

info_requests/_new.html

          <%= form_for(@info_request, remote: true, id: 'info-request-form') do |f| %>
            <input type="hidden" name="info_request[programme_id]" value="<%= @info_request.programme.id %>" />
  ... other form inputs ...
                      <button type="submit" id="info-request-submit" class="btn btn-primary btn-success">Yes, request information now!</button>
          <% end %>

<script>
  var init_info_request;

  init_info_request = function() {
    window.alert("init_info_request");

    $('#info-request-form').on('ajax:beforeSend', function(event, xhr, settings) {
      window.alert("ajax:beforeSend");
      $('#info-request-submit').text("Sending request...");
    });

    $('#info-request-form').on('ajax:success', function(event, data, status, xhr) {
      window.alert("ajax:success");
      $('#info-request-submit').text("Sent!");
    });

    $('#info-request-form').on('ajax:complete', function(event, xhr, status) {
      window.alert("ajax:complete");
    });

    $('#info-request-form').on('ajax:error', function(event, xhr, status, error) {
      window.alert("ajax:error");
    });

  }


  $(document).ready(function(){
    init_info_request();
  })
</script>

【问题讨论】:

    标签: jquery ruby-on-rails ajax forms


    【解决方案1】:

    从嵌套路由开始:

    resources :programmes
      resources :info_requests, shallow: true
    end
    

    这意味着我们将程序的 id 放在实际路径中。这意味着我们的路线现在是宁静且具有描述性的。

    class InfoRequestsController
      # use a callback instead of repeating yourself.
      before_action :set_programme, only: [:new, :index, :create]
    
      # GET /programmes/:programme_id/info_requests
      def index
        @info_requests = @programme.info_requests
      end
    
      # optional
      # GET /programmes/:programme_id/info_requests/new
      def new
        @info_request = @programme.info_requests.new
      end
    
      # POST /programmes/:programme_id/info_requests
      def create
        @info_request = @programme.info_requests.new(info_request_attributes) do |i|
          i.request = request
        end
        @coordinor = @programme.coordinator
    
        respond_to do |format|
          format.json do
            if @info_request.deliver
              head :created
            else
              head :unproccessable_entity
            end
          end
        end
      end
    
      private
    
      def set_programme
        @programme.includes(:info_requests)
                  .friendly.find(params[:programme_id])
      end
    
      def info_request_attributes
        @params.require(info_request).permit(
          :foo, :bar, :baz
        )
      end
    end
    

    我真的建议使用MailCatcher gem 进行开发。它是一个简单的 SMTP 服务器,它不会发送电子邮件而只是捕获它们。然后,您可以在 Web 浏览器中打开 http://127.0.0.1:1080 以在 GUI 中查看“外发”电子邮件。

    现在我们可以设置表单了

    # views/info_requests/_form.html.erb
    <%= form_for([info_request.programme, info_request], id: 'info-request-form', data: { remote: true, type: 'json' }) do |f| %>
      <button type="submit" class="btn btn-primary btn-success">Yes, request information now!</button>
    <% end %>
    

    如果您也有一个 new 模板,请不要调用您的部分 _new

    <%= render 'info_requests/form', info_request: @info_request %>
    

    让我们设置一个 ajax 处理程序:

    $(document).on('ajax:success', '#info-request-form', function(e, xhr, status){
      window.alert( "Thanks!" );
      $(this).attr('disabled',true);
    }).on('ajax:error', '#info-request-form', function(e, xhr, status){
      window.alert( "Please try again." );
      $(this).attr('disabled', false);
    });
    

    首先,我们从文档中委派事件处理程序 - 这使其具有幂等性,因此它可以与 turbolinks 一起正常工作。

    由于我们返回了正确的 HTTP 响应代码,jQuery UJS 将触发 ajax:successajax:error 选项卡。我鼓励您学习如何使用网络检查器中的网络选项卡,而不是使用警报语句进行调试。

    【讨论】:

    • 一般来说,学习如何在浏览器中使用检查器和登录rails而不是使用puts/alert会让你更有效率。
    • 谢谢!如何使用日志来检查我最终进入了代码的哪个“分支”?这就是我在这种情况下使用 puts(和 alert)的主要原因。
    【解决方案2】:

    好的,我想通了。有两个问题。

    1. 通过 jQuery,我正在筛选 #info-request-form 上的回调,因为这是我通过 form_for 中的参数设置的 ID。原来id 参数被忽略了。相反,表单的自动设置 ID 是 #new_info_request
    2. 我添加了views/programmes/_save.js.erb。它在提交表单时进行处理,因此我可以验证表单元素并显示反馈。 (我也可以在 _new.html.erb 的回调中这样做。)

    现在可以了!

    最多回答两个问题/问题:

    • 我没有使用浅层路由的原因是InfoRequests 在稍后阶段也可以用于其他资源,而不仅仅是Programmes。我以为我不需要专门为 AJAX 嵌套,但事实证明我实际上不需要。我是否会继续使用 InfoRequest 类等,目前仍然有点开放。
    • 您是只反对调用部分_new,还是反对它一开始就存在?因为有部分的原因是我需要能够从Programme#show 渲染它。不知道怎么做。

    【讨论】:

      猜你喜欢
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-25
      • 1970-01-01
      相关资源
      最近更新 更多