繁体   English   中英

Rails:如何通过引导模式添加对象?

[英]Rails: How to add an object through a bootstrap modal?

我是Rails的新手,我有这个Web应用程序,允许用户使用Rails 4创建新的打印作业。

应用程序/模型/job.erb

class Job < ActiveRecord::Base
  belongs_to :job_type
end

app / models / job_type.erb

class Job < ActiveRecord::Base
  has_many :jobs
end

在新的职位创建表单中,用户必须从列表中选择其新职位的职位类型,我设法将其抛出以下代码。

app / views / jobs / _form.html.erb

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@job) do |f| %>

      .....

      <div class="field">
        <%= f.label :job_type_id %><br>
        <%= f.collection_select :job_type_id, JobType.all,:id,:name %>
      </div>
      <!-- Modal -->
      <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
              <h4 class="modal-title" id="myModalLabel">Modal title</h4>
            </div>
            <div class="modal-body">
              ...
            </div>
            <div class="modal-footer">

            </div>
          </div>
        </div>
      </div>

    <% end %>

  </div>
</div>

通过一些咖啡脚本,我设法在“作业类型”菜单中添加了“其他”选项,这会触发模式#myModal以将新的JobType添加到数据库(如果不存在的话)...

应用/资产/javascript/jobs.coffee

$('#job_job_type_id').append("<option>Other</option>")
$('#job_job_type_id').change ->
  jobType = $('#job_job_type_id :selected').text()
  if jobType == "Other"
    $('#myModal').modal('show')
  else
    $('#myModal').modal('hide')

该规范运行良好,并启动了引导程序模式。 就是这样,我不知道下一步该怎么做?

我已经尝试了很多代码并审查了很多问题,但是我没有使这种模式能够添加新的JobType并更新列表,我认为需要对控制器和精美的AJAX代码进行一些修改出乎我的意料...

我在这里有一些问题

1)我应该在模态代码中添加些什么,以便能够向数据库中添加新的JobType,然后返回到新的Job创建表单并选择新创建的JobType

2)需要修改哪些控制器? 如何? 需要什么AJAX代码?

3)如何重构Job _form? 我可以将模式代码放在新的Partial中吗? 如果是,该如何实施?

希望您能为我提供帮助,多年来我一直在努力解决此问题。 谢谢

首先 ,在您的模式中设置按钮或表单以触发提交功能。

其次 ,设置/检查要用于AJAX方法的Routes / URL。

以及设置控制器功能以保存新的作业类型。

控制器中的示例:

def create
  job_type = JobType.new
  job_type.title = params[:job_type]
  if job_type.save
   render :json => job_type
  else
   render :json => "some error here."
  end
end

最后 ,使AJAX函数发送数据。

$("#add_new_job_type").click(function(){
    $.ajax({
        url: '/add_new_job_type',
        type: 'GET', // or POST
        data: {job_type: $("#field_contains_new_value").val()}
    }).done(function(data){
        // Do some validation for checking error response (like if statement)
        // Append the new data (job type to select option tag)
        new_job_type = "<option value="'+data.title+'">" + data.title + "</option>"
        $('#job_job_type_id').append(new_job_type);
        ....
        $("#myModal").modal('hide');
    });

});

注意: AJAX url中使用的add_new_job_type是自定义路由。

config / routes.rb (自定义路由)中:

match 'add_new_job_type' => 'job_types#add_new_job_type', :via => :post #or :get

JobTypes Controller中 ,您必须具有:

def add_new_job_type
  job_type = JobType.new
  job_type.title = params[:job_type]
  if job_type.save
   render :json => job_type
  else
   render :json => "some error here."
  end
end

根据需要修改代码。

如果我可以提供替代方案...

您的方法将需要一些高级编码方法,如果您对AJAX不满意,这可能是一条艰难的道路。

作为替代方案,我建议不要显示模式,而仅在现有表单中显示/隐藏文本框以容纳“其他”名称:

<input type="text" name="other_job_type" />

然后,当您提交表单时,如您所知,它将转到JobController#create(或对现有作业进行#update)。 在这里,您可以获取以下字段:

def create
  save_successful = false
  @job = Job.new params[:job]
  other_job_type = params[:other_job_type]
  if other_job_type
    new_job_type = JobType.new
    new_job_type.name = other_job_type
    save_successful = new_job_type.save
    @job.job_type = new_job_type
  end
  if save_successful && @job.save
    # redirect to success page
  else
    # render new/edit with error messages
  end
end

通过这种方式,只有在用户实际提交作业表格的情况下,才可以创建新的作业类型,这很好。

如果要对JobType强制执行验证(例如唯一名称),请使用save_successful模式。 如果用户尝试使用现有作业类型进行保存,则保存将失败。 您也可以为他们选择现有的,但是如果您选择这样做,我会留给您。

同样,所有这些都遵循您现在使用的相同模式,只是一个新的文本字段,并且在控制器中还有更多处理。

如果您愿意,我可以使用AJAX方法来使您的问题更详细地回答,因为这些步骤虽然很冗长,但是具有确定性,但是对于您的用例而言,这可能是过高的。 就是说,不管我对这种方法有何个人看法,我都不愿真正回答给定的问题,所以请让我知道。

好吧,首先,回答您的问题:

1)我应该在模态代码中添加些什么,以便能够向数据库中添加新的JobType,然后返回到新的Job创建表单并选择新创建的JobType

您的模态将添加一个表单,本质上是您可能在app/views/job_types/_form.html.erb拥有的app/views/job_types/_form.html.erb ,但是它将具有一个将通过AJAX提交而不是表单提交的按钮。

2)需要修改哪些控制器? 如何? 需要什么AJAX代码?

您将需要在job_types_controller中添加一个方法来处理上述AJAX调用。 它将需要:

  • 保存新的作业类型
  • 返回成功状态和新创建的实体给调用者。

3)如何重构Job _form? 我可以将模式代码放在新的Partial中吗? 如果是,该如何实施?

您需要一种方法,该方法在被调用时将一个新选项添加​​到列表框中。 您可以将模态代码部分或完全取决于您自己; 该决定与所有功能无关。

因此,您需要在这里做什么:

服务器(控制器):

1)在config/routes.rb中创建一个可以处理AJAX调用的方法。

resources :job_types do
  post :append, on: :collection
end

这将添加自定义资源路由。 因为我们是通过这种方式添加的,所以我们会自动获取URLHelper函数append_job_types_path

2)在controllers/job_types_controller.rb实现此方法,以保存新的JobType并将其(最重要的是ID)返回给调用者。

def append
  job_type = JobType.new
  job_type.name = params[:job_type_name]
  if job_type.save
    render :status => 201, :json => { id: job_type.id, name: job_type.name }
  else
    err_msg = job_type.errors.empty?? 'Save failed' : job_type.errors.full_messages.join('; ')
    render :status => 400, :json => { message: err_msg }
  end
end

如果保存顺利,新实体的ID和名称将作为JSON返回给调用方。 如果没有,我们将返回错误和任何验证消息。

现在,我们准备好利用这些方法...

客户(查看):

1)创建一个可以启动模式的按钮

您已经做到了!

2)向表单中添加一个可以提交工作类型的表格

<%= form_tag(append_job_types_path) do %>
  Enter Job Name:<br/>
  <input type="text" name="new_job_type_name" id="new_job_type_name" />
  <br/>
  <input type="button" value="Submit" id="append_job_type_submit" />
<% end %>

确实,由于我们是通过AJAX提交的,因此不必采用某种形式,但是您可能会通过使用AJAX获得一些样式帮助。 但是,此处的id属性对于后续步骤很重要。 请注意,我在这里使用form_tag而不是form_for 那是因为我不会在表单上附加任何内容(或为此提交)。

3)在提交(单击按钮时)上,将用户输入的名称发送到新的AJAX方法

在这里,我们将使用不引人注目的JavaScript将侦听器方法挂钩到“提交”按钮。 您可以将此代码放在视图的底部,也可以将其移至coffeescript:

javascript:
  $("#append_job_type_submit").click(function() {
    var name = $("#new_job_type_name").val();
    //TODO: validation on the name, ensure it's not blank, etc
    $.ajax({
      url: '/job_types/append',
      method: 'POST',
      data: {job_type_name: name},
      success: function(data) {
        //TODO: Handle success
      },
      error: function(err) {
        //TODO: Handle error
      }
    });
  });

在这里,我们将AJAX调用发送到服务器方法,并传递用户输入的名称。 请注意,我留出了一些空间供您进行简单验证,然后再提交

4)响应后,将新选项附加到列表框中。

这将从上面继续执行功能:

javascript:
  $("#append_job_type_submit").click(function() {
    var name = $("#new_job_type_name").val();
    //TODO: validation on the name, ensure it's not blank, etc
    $.ajax({
      url: '/job_types/append',
      method: 'POST',
      data: {job_type_name: name},
      success: function(data) {
        var sel = $("#job_type_id");
        sel.append('<option value="' + data.id + '">' + data.name + '</option>');
        $("#myModal").modal('hide');
        alert("New job type " + data.name + " created.");
        //TODO: probably be nice to auto-select this option; I'll leave that exercise to the alert reader
      },
      error: function(err) {
        alert(err.responseJSON.message);
      }
    });
  });

现在,用户可以从选择框中选择选项,并且新选项已保存到数据库中(无论他们是否创建新作业)。

免责声明 :我没有测试过此代码,甚至没有检查它是否可以编译。 但这应该可行,而且无论如何,这都是您要遵循的模式,因此,如果没有其他要求,至少您现在有方向。

现在,尽管如此,我仍然会建议我建议的另一种不使用AJAX的方法,因为它省去了大多数这些步骤,但这仅是我自己。 随时接受任何答案都可以帮助您按照自己的方式完成任务。

注意:我决定在aldrien的答案之外发布此内容,因为我发现一些差异足以证明这一点:

  • 成功和失败响应应返回成功/失败状态代码。 让它始终返回成功有点误导。 我认为状态码是任何REST设计的重要组成部分,甚至是很小的东西。
  • 我只建议使用match路线作为最后的手段。 足智多谋的路线更加清晰明了,它们也为您提供了更多便利。 另外,我喜欢/job_types下的路由,而不仅仅是在根目录下浮动。
  • 另外,更标准的事情应该是POST请求而不是GET; 毕竟,我们正在创建一个新实体。
  • 错误:append方法应为选项值产生data.id ,而不是data.title (根据原始代码应为data.name )。 否则,该值将不是ID,并且尝试保存将失败。

暂无
暂无

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

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