Ruby on Rails - custom PATCH action for form_for -
i'm working on spree e-commerce store built on ruby on rails , want custom action user can mark order complete straight checkout page without going through delivery etc. i've overridden checkout steps cannot 'checkout' button complete order sending order custom action in orders controller.
i'd think i've ticked off boxes: created patch action in routes.rb , checked rake routes make sure route exists. it's still telling me there no route.
the cart page won't load before submit anything, following error. i've spent day trying fix ideas great....
the error:
no route matches {:action=>"complete", :controller=>"spree/orders", :method=>:patch} routes.rb:
resources :orders member patch 'complete', to: 'orders#complete' end end rake routes:
prefix verb uri pattern controller#action spree / spree::core::engine complete_order patch /orders/:id/complete(.:format) orders#complete orders /orders(.:format) orders#index post /orders(.:format) orders#create new_order /orders/new(.:format) orders#new edit_order /orders/:id/edit(.:format) orders#edit order /orders/:id(.:format) orders#show patch /orders/:id(.:format) orders#update put /orders/:id(.:format) orders#update delete /orders/:id(.:format) orders#destroy html:
<%= form_for :order, url: {action: 'complete', method: :patch} |f| %> <% f.submit %> <% end %> i haven't created controller yet be:
def complete # mark order complete # redirect confirmation page end would appreciate help. thanks
edit: here updated view (app/views/orders/edit.html.erb):
<% @body_id = 'cart' %> <div data-hook="cart_container"> <h1><%= spree.t(:shopping_cart) %></h1> <% if @order.line_items.empty? %> <div data-hook="empty_cart"> <div class="alert alert-info"><%= spree.t(:your_cart_is_empty) %></div> <p><%= link_to spree.t(:continue_shopping), products_path, class: 'btn btn-default' %></p> </div> <% else %> <div data-hook="outside_cart_form"> <%= form_for @order, url: update_cart_path, html: { id: 'update-cart' } |order_form| %> <div data-hook="inside_cart_form"> <div data-hook="cart_items" class="table-responsive"> <%= render partial: 'form', locals: { order_form: order_form } %> </div> </div> <% end %> </div> <div id="empty-cart" class="col-md-6" data-hook> <%= form_tag empty_cart_path, method: :put %> <p id="clear_cart_link" data-hook> <%= submit_tag spree.t(:empty_cart), class: 'btn btn-default' %> <%= spree.t(:or) %> <%= link_to spree.t(:continue_shopping), products_path, class: 'continue' %> </p> <% end %> </div> <div id="complete-order"> complete order here - submit custom controller <%= @order.id %> <%= form_for @order, url: complete_order_path(@order) |f| %> <% f.submit %> <% end %> </div> <% end %> </div> here whole controller:
module spree class orderscontroller < spree::storecontroller before_action :check_authorization rescue_from activerecord::recordnotfound, :with => :render_404 helper 'spree/products', 'spree/orders' respond_to :html before_action :assign_order_with_lock, only: :update skip_before_action :verify_authenticity_token, only: [:populate] def show @order = order.includes(line_items: [variant: [:option_values, :images, :product]], bill_address: :state, ship_address: :state).find_by_number!(params[:id]) end def complete @order = current_order end def update if @order.contents.update_cart(order_params) respond_with(@order) |format| format.html if params.has_key?(:checkout) @order.next if @order.cart? redirect_to checkout_state_path(@order.checkout_steps.first) else redirect_to cart_path end end end else respond_with(@order) end end # shows current incomplete order session def edit @order = current_order || order.incomplete. includes(line_items: [variant: [:images, :option_values, :product]]). find_or_initialize_by(guest_token: cookies.signed[:guest_token]) associate_user end # adds new item order (creating new order if none exists) def populate order = current_order(create_order_if_necessary: true) variant = spree::variant.find(params[:variant_id]) quantity = params[:quantity].to_i options = params[:options] || {} # 2,147,483,647 crazy. see issue #2695. if quantity.between?(1, 2_147_483_647) begin order.contents.add(variant, quantity, options) rescue activerecord::recordinvalid => e error = e.record.errors.full_messages.join(", ") end else error = spree.t(:please_enter_reasonable_quantity) end if error flash[:error] = error redirect_back_or_default(spree.root_path) else respond_with(order) |format| format.html { redirect_to cart_path } end end end def empty if @order = current_order @order.empty! end redirect_to spree.cart_path end def accurate_title if @order && @order.completed? spree.t(:order_number, :number => @order.number) else spree.t(:shopping_cart) end end def check_authorization order = spree::order.find_by_number(params[:id]) || current_order if order authorize! :edit, order, cookies.signed[:guest_token] else authorize! :create, spree::order end end private def order_params if params[:order] params[:order].permit(*permitted_order_attributes) else {} end end def assign_order_with_lock @order = current_order(lock: true) unless @order flash[:error] = spree.t(:order_not_found) redirect_to root_path , return end end end end edit
it has become apparent since posted question in fact need declare routes in special way, despite rake routes showing them correct.
in routes.rb, add this:
spree::core::engine.routes.draw # add custom routes here, e.g. '/terms-and-conditions' => 'home#terms', as: :terms end this allow use <%= link_to("terms", terms_path) %> helper.
see adding routes rails' spree e-commerce more details. wish documentation better on mentioned apart on far can tell.
this happens because not passing object form. there's no id parameter in route, , router fails make match.
your route defined member action, means expects id parameter. passing symbol instead.
<%= form_for :order <-- problem the clue in error message:
no route matches {:action=>"complete", :controller=>"spree/orders", :method=>:patch} notice how there's no id parameter in hash in error message?
to solve this, provide object form. example:
<%= form_for @order, url: complete_order_path(@order) |f| %> where @order instance variable set in controller.
on side note, can define routes so:
resources :orders member patch :complete end # or, since it's 1 route... patch :complete, on: :member end notice can use symbols, , don't have specify controller because it's inferred resource name.
finally, don't need tell form method should patch. rails infers object passed in, in case @order. if it's new, method post, otherwise patch.
Comments
Post a Comment