Need Method Create And Not Update When Instance Actually Does Exist
Solution 1:
If I understand this correctly, you want to achieve the following:
Display a form for creating new car models. In this form, the user enters a year; the system then loads all makes for that year from the server and presents a select drop down for the user to choose a make from.
The Car model belongs_to ymm_make, so we include the selected ymm_make_id when the form is submitted.
Here is how I would solve this. I will use the standard Rails form helpers, so that we have one less abstraction layer to worry about.
The form (with 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 %>
For the year search field, I use text_field_tag
instead of f.text_field
, because I don't want the search field value to be submitted as a part of the car when the whole form is submitted. I leave the dropdown field empty for now - we will populate that through Javascript and JSON.
For the list of makes, I'll make a resource controller that returns JSON:
class YmmMakesController < ApplicationController
respond_to :json
def index
@makes = YmmMake.makes(params[:year])
respond_with @makes
end
end
Don't forget a route.rb entry for this controller, e.g.
namespace :admin do
resources :ymm_makes, only: :index
end
We'll make <select>
options out of our JSON in 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('') );
});
});
With all this in place, you should have a working form for creating new cars that are associated with a YmmMake model object.
A few observations about your existing code:
Nested forms
<%= simple_form_for [:admin, @car] do |f| %>
<%= render partial: "makes", locals: {form: 'new_admin_car', car_id: car_id} %>
<% end %>
If I see this correctly, your 'makes' partial also contains a form, so you are creating a <form>
nested in a <form>
. HTML does not allow that.
Wrong closing tag order
<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>
The closing </div>
must come before the <% end %>
. If you build invalid HTML, you risk strange visual behaviour and Javascript errors.
Redundant arguments
<%= simple_form_for [:admin, @car],
html: {id: 'new_admin_car', class: 'form-vertical', method: post},
do |f| %>
"id" and "method" should be the default values. Leaving them out makes the code easier to read.
Invalid <input>
attributes through input_html
<%= f.input(:stock_number, {input_html: {form: 'new_admin_car', car: @car, value: nil}, autocomplete: :off, placeholder: 'Stock number?'}) %>
I'm not familiar with simple_form, but from what I see, input_html
is used to add attributes to the input element. Lines like the above would thus produce a text input with an invalid car
attribute. The form
attribute should not be necessary anymore as soon as you remove the nested form.
Wrong HTTP method
$.post('/admin/cars/make_list/'
You load your makes through a POST AJAX request. For requests that only return data, but do not change anything, GET is usually more appropriate.
Solution 2:
In your form you can specify the path the submit button should go to:
<%= simple_form_for [:admin, @car], url: create_action_path
...
Solution 3:
I think your answer is fairly simple, to create
instead of update
, just clear the model's id
.
Example: @car.id = nil
Post a Comment for "Need Method Create And Not Update When Instance Actually Does Exist"