Rails forms: updating collection_select options ba

2020-06-26 10:58发布

I'm just starting to learn Rails and I get along quite well with the built-in tools, Javascript and AJAX however are very new to me. Here's the problem:

I have an order form. Every order belongs to a contact and can have a different billing and shipping address. collection_select boxes are used to set these values. All of this works fine if I wouldn't mind the necessary page reload to trim down the available address options, which should be limited to the addresses that belong to the selected contact.

What is the simplest and easiest to maintain option to make this work without page reloads?

This is what I tried to ajaxify the form before I got stuck. Let's start with an extract from views/orders/edit.html.erb:

<%= nested_form_for @order, remote: true do |f| %>
...
<%= f.label :contact_id, "Händler" %>
<%= f.collection_select(:contact_id, Contact.order(:name), :id, :name) %>

<%= f.label :billing_address_id, "Rechnungsanschrift" %>    
<%= f.collection_select(:billing_address_id, Address.where(contact_id: @order.contact_id), :id, :name) %>
...
<% end %>

I omitted the shipping address select box as it would be same as the billing dropdown. Let's just focus on that for now.

Here's the update action in controllers/orders_controller.rb:

def update
  @order = Order.find(params[:id])

  respond_to do |format|

    if @order.update_attributes(order_params)
      format.html { redirect_to edit_order_path, notice: "Auftrag aktualisiert." }
      format.json { render json: @order }
      format.js
    else
      render 'edit'
    end
  end
end

I try to watch the contact select box for changes in order to save them immediately hoping the address selects would reflect those changes immediately too. This observer is located in assets/javascript/orders.js.erb:

$('#order_contact_id').change(function() {
  $(this).parents('form:first').submit();
});

At that point I was hoping that this would be enough and data was saved already, but apparently Rails expects me to define some further instructions in views/orders/update.js.erb - here I'm helpless. This is what I came up with:

$('#order_billing_address_id').replaceWith('<%= escape_javascript(collection_select(:order, :billing_address_id, Address.where(contact_id: @order.contact_id), :id, :name)) %>');

order_billing_address_id is the id of the collection_select box for the billing addresses and I basically just want to refresh the built-in rails collection_select tag.

This actually kind of works - if I select a different contact the address box is populated with its respective address instantly - however only if the contact doesn't have more than one associated address. When I select a contact with multiple address options the address select box sticks with the options from the last contact that had only one address. If I refresh the page manually though it shows the correct values, even for contacts with multiple addresses. So the data is definitely saved, which tells me that my update.js.erb probably is the problem.

I watched the output of the rails dev server while selecting various contacts and the data seems to be processed, saved and retrieved just fine - I can't make out any differences in those server logs between single-address-contacts and multiple-address-contacts. According to those logs the queries and retrieved record IDs and collection match up as expected.

What am I doing wrong here? Or more generally, is there a better approach/practice to what I'm trying to do? Please bear in mind that I'm very new to Rails and even more Javascript. Your help is very much appreciated.

0条回答
登录 后发表回答