5

I am building a spree shop into an exiting Rails application, and I need to access link_to_cart from outside of the Spree engine.

link_to_cart can be found here: spree/core/app/helpers/spree/base_helper.rb

Since I have modified the styling in link_to_cart, I also created:

  #helpers/spree/base_helper_decorator.rb
  module Spree
    module BaseHelper
      def link_to_cart(text = nil)
      text = text ? h(text) : Spree.t('cart')
      css_class = nil

      if simple_current_order.nil? or simple_current_order.item_count.zero?
        text = "#{text}: (#{Spree.t('empty')})"
        css_class = 'empty'
      else
        text = "<i class='fa fa-shopping-cart'></i> #{text}: (#{simple_current_order.item_count})  <span class='amount'>#{simple_current_order.display_total.to_html}</span>".html_safe
        css_class = 'full'
      end

      link_to text.html_safe, spree.cart_path, :class => "cart-info #{css_class} btn btn-small btn-success pull-right", style: "margin-left:10px;"
    end
  end
end

I have tried doing stuff like Spree::BaseHelper.link_to_cart outside of the engine, but I keep getting undefined local variable or method 'link_to_cart'

I found this on a different StackOverflow question, and it seems promising, but I'm not sure how to modify it for my needs:

module MyEngine
  class Engine < Rails::Engine
    initializer 'my_engine.action_controller' do |app|
      ActiveSupport.on_load :action_controller do
        helper MyEngine::ImportantHelper
      end
    end
  end
end
Community
  • 1
  • 1
Abram
  • 39,950
  • 26
  • 134
  • 184

5 Answers5

7

Ok, thanks Ben for getting me on the right track. Here was my solution:

# class ApplicationController < ActionController::Base
   include Spree::Core::ControllerHelpers::Order
   include Spree::Core::ControllerHelpers::Auth
   helper Spree::BaseHelper
   helper Spree::StoreHelper

Update

I ran into an issue with current_store being undefined outside of the engine. I'm not sure how to solve this properly, but in the meantime I've just added the following to stop spree from calling current_store:

module Spree
  module Core
    module ControllerHelpers
      module Order
        def current_order_params
          { currency: current_currency, guest_token: cookies.signed[:guest_token], store_id: Spree::Store.first, user_id: try_spree_current_user.try(:id) }
        end
      end
    end
  end
end

Also helper Spree::StoreHelper seems to no longer be required to display the cart button and current orders..

Abram
  • 39,950
  • 26
  • 134
  • 184
  • Ahha, the fabled stackoverflow answer with the exact answer you needed! Where did you add the second code snippet please? I tried orders controller decorator but no cigar :( – kimadactyl Feb 17 '16 at 14:10
  • Cannot recall. Try lib – Abram Feb 17 '16 at 14:12
  • Hmm no luck. Tried various combinations within app and no luck too. How strange. – kimadactyl Feb 17 '16 at 14:23
  • 1
    Adding the current_order_params function to the application controller and manually specifying current_currency is working for me for now! – kimadactyl Feb 17 '16 at 14:33
  • Thanks for this! It got me on the right track. It seems some updates to spree made it so you have to add `include Spree::Core::ControllerHelpers::Common` . This changes the way your entire app is rendered, though. – Ryan Dec 29 '16 at 21:43
2

You need to do two things

  1. Create your override
  2. Make your override accessible within the main app

Step 1: My Spree overrides are in the overrides folder in my main app. The override should call module_eval on the module that you are decorating.

#overrides/base_helper_decorator.rb
Spree::BaseHelper.module_eval do

  def link_to_cart(text = nil)
    #Your customizations here
  end

end

Step 2: Add one of the lines below to your main app ApplicationController to access your decorated helper.

helper_method :link_to_cart # Add only the link_to_cart method 

helper 'spree/base'         # Add all methods (your decoration plus the default methods) 
                            # from the Spree BaseHelper module to your main app
Ben Robbins
  • 2,600
  • 2
  • 24
  • 26
  • Not sure why, but after doing everything I am still getting undefined local variable or method `link_to_cart' – Abram Sep 01 '14 at 17:42
2

There have been some updates since Abram left his answer. It got me on the right track but I had a few hiccups. The main one was current_currency being undefined.

application_controller.rb

class ApplicationController < ActionController::Base
  include Spree::Core::ControllerHelpers::Order
  include Spree::Core::ControllerHelpers::Auth
  include Spree::Core::ControllerHelpers::Store
  include Spree::Core::ControllerHelpers::Common
  helper Spree::BaseHelper

I overrode the Spree navbar and used the one for my main app.

It started working when I added include Spree::Core::ControllerHelpers::Common. Unfortunately, this renders all views through the spree spree_application.html.erb layout. You may have to override and tinker a bit with this view.

Also, all of the css comes from spree at this point. You'll have to move your custom css into the spree namespace and @import it.

Ryan
  • 541
  • 4
  • 4
1

You will have to include the right helpers in your main application outside the engine too. In the upcoming version 3.2.0 of spree I just had to add:

# class ApplicationController < ActionController::Base
  include Spree::Core::ControllerHelpers::Store
  include Spree::Core::ControllerHelpers::Order
  include Spree::Core::ControllerHelpers::Auth

to my ApplicationController to make link_to_cart work everywhere. You'll need to include more then one helper class, because for example current_store (used by other helpers) is defined in Spree::Core::ControllerHelpers::Store, so add that too to get rid of any errors.

amoebe
  • 4,857
  • 5
  • 37
  • 42
0

You can add this to your main_app to access the cart.

<%= link_to "Cart", spree.cart_path %>

katharine
  • 51
  • 2
  • 2