[英]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">×</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的答案之外发布此内容,因为我发现一些差异足以证明这一点:
match
路线作为最后的手段。 足智多谋的路线更加清晰明了,它们也为您提供了更多便利。 另外,我喜欢/job_types
下的路由,而不仅仅是在根目录下浮动。 data.id
,而不是data.title
(根据原始代码应为data.name
)。 否则,该值将不是ID,并且尝试保存将失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.