Search code examples
ruby-on-railsspree

Spree 3.1: Adding select tag to shipment form in delivery step


I am trying to add one more select tag for city in shipment form in checkout delivery.

#views/spree/checkout/_delivery.html.erb

<%= form.fields_for :shipments do |ship_form| %>
  <% ship_form.object.shipping_rates.each do |rate| %>
    <tr class="stock-item">
        <td class="shipment-button"><%= ship_form.radio_button :selected_shipping_rate_id, rate.id %></td>
        <td class="rate-name"><%= rate.name %></td>
        <td class="item-qty"></td>
        <td class="rate-cost"><%= rate.display_cost %></td>
    </tr>
    <% if rate.shipping_method_id == 4 %>
        <tr id="city" style="display: none">
            <td></td>
            <td>
            <%= ship_form.select :selected_city_id, options_from_collection_for_select(@cities, "id", "name"), { :include_blank => true }, { :class => "select-city" } %>
            </td>
            <td></td>
            <td></td>
        </tr>
    <% end %>
<% end %>

model shipment:

#models/spree/shipment.rb

def selected_shipping_rate
  shipping_rates.where(selected: true).first
end

def selected_shipping_rate_id
  selected_shipping_rate.try(:id)
end

def selected_city_id
  selected_shipping_rate.try(:selected_city_id)
end

checkout controller:

#controller/spree/checkout_controller.rb

def update
  if @order.update_from_params(params, permitted_checkout_attributes, request.headers.env)
    @order.temporary_address = !params[:save_user_address]
    unless @order.next
      flash[:error] = @order.errors.full_messages.join("\n")
      redirect_to(checkout_state_path(@order.state)) && return
    end
    if @order.completed?
      @current_order = nil
      flash.notice = Spree.t(:order_processed_successfully)      
      flash['order_completed'] = true
      redirect_to completion_route
    else
      redirect_to checkout_state_path(@order.state)
    end
  else
    render :edit
  end
end

Select box is for choosing city where shipping method is available.

I added new column in table spree_shipments and I also added method selected_city_id in models/spree/shippment.rb and permitted new parameters in initializer.

But when I try to get @order.shipments.order("created_at").last.selected_city_id I get NoMethodError: undefined method selected_city_id.

Prams after submit looks like this:

"order"=>{
   "shipments_attributes"=>{
   "0"=>{"selected_city_id"=>"10", 
   "selected_shipping_rate_id"=>"10",
   "id"=>"4"}
   }
}

I think I'm missing something in here... Please can someone help me, how to save selected_city_id in db? Should it be saved in different table (spree_shipping_rates)?

Thanks


Solution

  • Solution:

    I added one more method in Shipment model

    #models/spree/shipment.rb
    
    def selected_shipping_rate
      shipping_rates.where(selected: true).first
    end
    
    def selected_shipping_rate_id
      selected_shipping_rate.try(:id)
    end
    
    def selected_city_id
      selected_shipping_rate.try(:selected_city_id)
    end
    
    def selected_city_id=(id)
      selected_shipping_rate.update(selected_city_id: id)
    end