2014-09-10 68 views
0

Ruby 2.0.0,Rails 4.0.3需要方法创建并且在实例确实存在时不更新

我有一个_new部分。但是,我用一个实际存在的实例来渲染它。这是必要的,以便我可以通过View和Controller之间的JavaScript传递实例ID,因为我实际上不能传递实例本身。我只需在新方法中调用Class.first,以便通过该过程使用现有实例。

我的问题是_new部分提交按钮识别出该实例已经存在。这导致它更新而不是创建。按钮字面上说更新。按下时,它将路由到更新方法。这不是我想要的。我想要创建方法,在那里我将创建一个填充了收集参数的新实例。

怎么办?我是否仅仅携带一个虚拟实例来启动流程?如果是这样,什么是正确的解决方案?如果这是可接受的,我该如何强制按钮创建而不是更新?

赞赏所有的帮助和意见。

编辑:我试过按钮上的变体,试图强制它触发到新的方法。它继续着火更新。我最后的失败努力是:

<button type="submit" formaction="new_admin_car_path" class="btn btn-default btn btn-primary">Create Car</button> 

...编辑完...

形式为:

<div class="span8"> 
    <% car_id = @car.id %> 
    <%= simple_form_for [:admin, @car], 
         defaults: {label: false}, 
         html: {id: 'new_admin_car', class: 'form-vertical', method: post}, 
         wrapper: :vertical_form, 
         wrapper_mappings: { 
           check_boxes: :vertical_radio_and_checkboxes, 
           radio_buttons: :vertical_radio_and_checkboxes, 
           file: :vertical_file_input, 
           boolean: :vertical_boolean 
         } do |f| %> 
     <%= f.input(:stock_number, {input_html: {form: 'new_admin_car', car: @car, value: nil}, autocomplete: :off, placeholder: 'Stock number?'}) %> 
     <%= f.input(:ymm_year_id, {input_html: {form: 'new_admin_car', car_id: car_id, value: nil}, collection: YmmYear.all.order("year desc").collect{|c| [c.year, c.id]}, prompt: "Year?"}) %> 
     <%= render partial: "makes", locals: {form: 'new_admin_car', car_id: car_id} %> 
     <%= render partial: "models", locals: {form: 'new_admin_car', car_id: car_id} %> 
     <%= f.association(:color, {input_html: {form: 'new_admin_car', value: nil}, autocomplete: :off, prompt: 'Color?'}) %> 
     <div class="col-xs-6 col-sm-3"> 
     <br/> 
     <input type="submit" form="new_admin_car" value="Create Car" class="btn btn-default btn btn-primary"> 
    <% end %> 
    </div> 
</div> 

使部分:

<% unless car_id.blank? %> 
    <% car = Car.find(car_id) %> 
    <%# car.ymm_make_id = nil %> 
    <%= simple_form_for [:admin, car], 
         defaults: {label: false}, 
         remote: true do |f| %> 
     <% makes ||= "" %> 
     <% make = "" %> 
     <% make = car.make_id if car.class == Car and Car.exists?(car.id) %> 
     <% if !makes.blank? %> 
      <%= f.input :ymm_make_id, {input_html: {form: form, car: car, car_id: car.id, value: make}, collection: makes.collect { |s| [s.make, s.id] }, prompt: "Make?"} %> 
     <% else %> 
      <%= f.input :ymm_make_id, {input_html: {form: form, car: car, car_id: car.id, value: make}, collection: [], prompt: "Make?"} %> 
     <% end %> 
    <% end %> 
<% end %> 

控制器租车方法新的地方清除所有领域:

def new 
    @car = Car.first 
    @car.clear 
    end 

呈现的表单: enter image description here

的JavaScript的形式是:

// when the #year field changes 
$("#car_ymm_year_id").change(function() { 
    // make a GET call and replace the content 
    // First select identifies what has been selected, or fired 
    var year = $('select#car_ymm_year_id :selected').val(); 
    // Pull the variables from the input_html tag 
    var form = $('select#car_ymm_year_id').attr("form"); 
    var car_id = $('select#car_ymm_year_id').attr("car_id"); 
    // Routes to the controller action 
    $.post('/admin/cars/make_list/', 
     { 
      form: form, 
      year: year, 
      car_id: car_id 
     }, 
     function (data) { 
      $("#car_ymm_make_id").html(data); 
     }); 
    return false; 
}); 

控制器的方法:

def make_list 
    makes = YmmMake.makes(params[:year]) 
    #@car = Car.find(params[:car_id]) 
    render partial: "makes", locals: {car_id: params[:car_id], form: params[:form], makes: makes} 
    end 
+0

您能否通过在视图和控制器之间通过JavaScript传递实例ID来详细说明您的意思吗?我们可能能够在那里找到更好的解决方案,并首先避免整个事情。使用现有的实例,然后强制表单助手将其视为一个带有撬棒的新实例,这听起来确实是一个糟糕的主意。 – janfoeh 2014-09-13 13:55:47

+0

@janfoeh我试图保持简单,但这不工作,所以...我已经更新了问题,包括所有相关的部分,形式和方法。问题是我有一系列依赖选择。当我为汽车选择一年的时候,它将返回所有“制造”或那年制造汽车的制造商。等等......为此,我使用一个实例。请参阅代码并让我知道你是否还有其他问题。谢谢。 – 2014-09-13 14:32:56

+0

我认为你的代码有一些误解和彻底的错误。我会创建一个空白的,干净的版本,试图实现你的目标,并尝试清除这些内容。 – janfoeh 2014-09-13 15:44:32

回答

1

如果我理解正确此,要实现以下目标:

显示用于创建新车型的形式。在这种形式下,用户输入一年;然后系统从服务器加载当年的所有品牌,并提供一个选择下拉菜单供用户选择一个品牌。

汽车模型belongs_to ymm_make,所以我们在提交表单时包含了所选的ymm_make_id。

下面是我将如何解决这个问题。我将使用标准的Rails表单助手,这样我们就不用担心抽象层了。

形式(与Car.new):

<%= form_for [:admin, Car.new] do |f| %> 
    <%= f.text_field :stock_number, autocomplete: "off", placeholder: "Stock number?" %> 
    <%= text_field_tag :year_search, nil, placeholder: "Year" %> 
    <%= f.select :ymm_make_id %> 

    <!-- skipping models and colors here for the sake of brevity --> 

    <%= f.submit "Create" %> 
<% end %> 

今年首搜索领域,我用text_field_tag代替f.text_field,因为我不想让搜索字段值提交作为汽车的一部分做当整个表格被提交时。现在我将下拉字段留空 - 我们将通过Javascript和JSON填充该字段。

对于品牌的名单,我会返回一个JSON资源控制器:

class YmmMakesController < ApplicationController 
    respond_to :json 

    def index 
    @makes = YmmMake.makes(params[:year]) 

    respond_with @makes 
    end 
end 

不要忘了这个控制器,例如route.rb进入

namespace :admin do 
    resources :ymm_makes, only: :index 
end 

我们会让<select>选择我们的JSON在Javascript:

$("input[name=year_search]").change(function() { 

    // send a GET request to /admin/ymm_makes with the 'year' parameter 
    // set to the value of the year_search text field 
    $.getJSON("/admin/ymm_makes", {year: $(this).val()}, function(data) { 
     var options_html = []; 

     // iterate over the JSON that we received back; each entry is one 'ymm_make' 
     // in JSON form 
     $.each(data, function(index, make) { 
     // make a new <option> tag for each make and push it into the options_html array 
     // I assume here that YmmMake has an attribute called 'name' you want to display 
     options_html.push("<option value='" + make.id + "'>" + make.name + "</option>"); 
     }); 

     // put all our generated <options> tags into the <select> tag 
     $('select#car_ymm_make_id').html(options_html.join('')); 
    }); 

}); 

有了这一切之后,就应该有创建与一个YmmMake模型相关联的新车工作形式目的。

你的现有代码的一些意见:

嵌套形式

<%= simple_form_for [:admin, @car] do |f| %> 
    <%= render partial: "makes", locals: {form: 'new_admin_car', car_id: car_id} %> 
<% end %> 

如果我看到这个正确的,你的“使”部分还包含一个表单,所以您要创建一个<form>嵌套在<form>。 HTML does not allow that

错误关闭标签顺序

 <div class="col-xs-6 col-sm-3"> 
     <br/> 
     <input type="submit" form="new_admin_car" value="Create Car" class="btn btn-default btn btn-primary"> 
    <% end %> 
    </div> 

收盘</div>必须出现在<% end %>之前。如果您构建了无效的HTML,则会冒着奇怪的视觉行为和Javascript错误。

冗余参数

<%= simple_form_for [:admin, @car], 
         html: {id: 'new_admin_car', class: 'form-vertical', method: post}, 
         do |f| %> 

“id” 和 “方法” 应该是默认值。将它们排除在外将使代码更易于阅读。

无效<input>属性通过input_html

<%= f.input(:stock_number, {input_html: {form: 'new_admin_car', car: @car, value: nil}, autocomplete: :off, placeholder: 'Stock number?'}) %> 

我不熟悉simple_form,但是从我所看到的,input_html用于属性添加到输入元素。像上面这样的行会因此产生一个带有无效car属性的文本输入。删除嵌套表单后,应该不再需要form属性。

$.post('/admin/cars/make_list/' 

您通过POST AJAX请求加载您的品牌错误的HTTP方法。对于只返回数据但不改变任何内容的请求,GET通常更合适。

+0

好吧,看起来很有趣,我正在努力实现它。但是,我的应用程序基于简单表单。建议在其中实施这个? – 2014-09-14 15:56:54

+0

我建议先从内置的表单助手开始,如上所述。只要你有一个工作基线,你可以重构它以使用简单表单,直到它再次工作。这两种方法不是相互排斥的,可以并行使用。 – janfoeh 2014-09-14 18:18:27

+0

实施这个建议有几个问题,但最终它比旧的代码有了很大的改进。谢谢。 – 2014-09-18 09:53:42

0

在你的表格,您可以指定路径提交按钮应该去到:

<%= simple_form_for [:admin, @car], url: create_action_path 

... 
+0

没有改变任何东西。谢谢。 – 2014-09-13 13:44:08

0

我认为你的回答很简单,到create而不是update,只要清除模型的id即可。
示例:@car.id = nil

相关问题