@spree/docs 0.1.75 → 0.1.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/developer/admin/admin.md +0 -1
- package/dist/developer/admin/extending-ui.md +0 -119
- package/dist/developer/admin/tables.md +0 -2
- package/dist/developer/core-concepts/slugs.md +1 -1
- package/dist/integrations/integrations.md +1 -1
- package/package.json +1 -1
- package/dist/developer/contributing/updating-extensions.md +0 -67
- package/dist/developer/customization/v4/admin-panel.md +0 -78
- package/dist/developer/customization/v4/authentication.md +0 -210
- package/dist/developer/customization/v4/checkout.md +0 -212
- package/dist/developer/customization/v4/deface.md +0 -251
- package/dist/developer/customization/v4/images.md +0 -86
- package/dist/developer/customization/v4/storefront.md +0 -450
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Checkout Flow
|
|
3
|
-
description: Learn how to customize the checkout process in Spree.
|
|
4
|
-
version: v4
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
The Spree checkout process has been designed for maximum flexibility. It's been redesigned several times now, each iteration has benefited from the feedback of real-world deployment experience. It is relatively simple to customize the checkout process to suit your needs. Secure transmission of customer information is possible via SSL and credit card information is never stored in the database.
|
|
10
|
-
|
|
11
|
-
## The Checkout Flow DSL
|
|
12
|
-
|
|
13
|
-
Spree comes with a new checkout DSL that allows you to succinctly define the different steps of your checkout. This new DSL allows you to customize _just_ the checkout flow, while maintaining the unrelated admin states, such as "canceled" and "resumed", that an order can transition to. Ultimately, it provides a shorter syntax compared with overriding the entire state machine for the `Spree::Order` class.
|
|
14
|
-
|
|
15
|
-
The default checkout flow for Spree is defined like this, adequately demonstrating the abilities of this new system:
|
|
16
|
-
|
|
17
|
-
```ruby
|
|
18
|
-
checkout_flow do
|
|
19
|
-
go_to_state :address
|
|
20
|
-
go_to_state :delivery
|
|
21
|
-
go_to_state :payment, if: ->(order) {
|
|
22
|
-
order.update_totals
|
|
23
|
-
order.payment_required?
|
|
24
|
-
}
|
|
25
|
-
go_to_state :confirm, if: ->(order) { order.confirmation_required? }
|
|
26
|
-
go_to_state :complete
|
|
27
|
-
remove_transition from: :delivery, to: :confirm
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
we can pass a block on each checkout step definition and work some logic to figure if the step is required dynamically. e.g. the confirm step might only be necessary for payment gateways that support payment profiles.
|
|
31
|
-
|
|
32
|
-
These conditional states present a situation where an order could transition from delivery to one of payment, confirm or complete. In the default checkout, we never want to transition from delivery to confirm, and therefore have removed it using the `remove_transition` method of the Checkout DSL. The resulting transitions between states look like the image below:
|
|
33
|
-
|
|
34
|
-
These two helper methods are provided on `Spree::Order` instances for your convenience:
|
|
35
|
-
|
|
36
|
-
* `checkout_steps` - returns a list of all the potential states of the checkout.
|
|
37
|
-
* `has_step?` - Used to check if the current order fulfills the requirements for a specific state.
|
|
38
|
-
|
|
39
|
-
If you want a list of all the currently available states for the checkout, use the `checkout_steps` method, which will return the steps in an array.
|
|
40
|
-
|
|
41
|
-
## Default Checkout Steps
|
|
42
|
-
|
|
43
|
-
The Spree checkout process consists of the following steps. With the exception of the Registration step, each of these steps corresponds to a state of the [Order object](../../core-concepts/orders.md):
|
|
44
|
-
|
|
45
|
-
* Registration Optional - only if using [spree_auth_devise](https://github.com/spree/spree_auth_devise) extension, can be toggled through the `Spree::Auth::Config[:registration_step]` configuration setting
|
|
46
|
-
* Address Information
|
|
47
|
-
* Delivery Options Shipping Method
|
|
48
|
-
* Payment
|
|
49
|
-
* Confirmation
|
|
50
|
-
|
|
51
|
-
The following sections will provide a walk-through of checkout from a user's perspective, and offer some information on how to configure the default behavior of the various steps.
|
|
52
|
-
|
|
53
|
-
### Registration
|
|
54
|
-
|
|
55
|
-
> **INFO:** This section only applies when using `spree_frontend` and `spree_auth_devise` gems.
|
|
56
|
-
|
|
57
|
-
Prior to beginning the checkout process, the customer will be prompted to create a new account or to log in to their existing account. By default, there is also a "guest checkout" option that allows users to specify only their email address if they do not wish to create an account.
|
|
58
|
-
|
|
59
|
-
Technically, the registration step is not an actual state in the `Spree::Order` state machine. The `spree_auth_devise` gem (an extension that comes with Spree Starter by default) adds the `check_registration` before filter to all actions of `Spree::CheckoutController` except for obvious reasons the `registration` and `update_registration` actions, which redirects to a registration page unless one of the following is true:
|
|
60
|
-
|
|
61
|
-
* `Spree::Auth::Config[:registration_step]` preference is not `true`
|
|
62
|
-
* user is already logged in
|
|
63
|
-
* the current order has an email address associated with it
|
|
64
|
-
|
|
65
|
-
The method is defined like this:
|
|
66
|
-
|
|
67
|
-
```ruby
|
|
68
|
-
def check_registration
|
|
69
|
-
return unless Spree::Auth::Config[:registration_step]
|
|
70
|
-
return if spree_current_user || current_order.email
|
|
71
|
-
store_location
|
|
72
|
-
redirect_to spree.checkout_registration_path
|
|
73
|
-
end
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
#### Disabling guest checkout
|
|
77
|
-
|
|
78
|
-
To completely disable guest checkout and require registration for checkout, you need to change Spree configuration in `config/initializers/spree.rb`:
|
|
79
|
-
|
|
80
|
-
```ruby
|
|
81
|
-
Spree::Config[:allow_guest_checkout] = false
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Address Information
|
|
85
|
-
|
|
86
|
-
This step allows the customer to add both their billing and shipping information. Customers can click the "use billing address" option to use the same address for both.
|
|
87
|
-
|
|
88
|
-
The address fields include a select box for choosing state/province. If there are no states configured for a particular country, the select box will be replaced by a text field instead.
|
|
89
|
-
|
|
90
|
-
The list of countries that appear in the country select box can also be configured. Spree will list all countries by default, but you can configure exactly which countries you would like to appear. The list can be limited to a specific set of countries by [setting the Store's checkout zone](../../core-concepts/stores.md#checkout-configuration). Spree assumes that the list of billing and shipping countries will be the same. You can always change this logic via class decorator if this does not suit your needs.
|
|
91
|
-
|
|
92
|
-
### Delivery Options
|
|
93
|
-
|
|
94
|
-
During this step, the user may choose a delivery method. Spree assumes the list of shipping methods to be dependent on the shipping address.
|
|
95
|
-
|
|
96
|
-
### Payment
|
|
97
|
-
|
|
98
|
-
This step is where the customer provides payment information. This step is intentionally placed last in order to minimize security issues with credit card information. Credit card information is never stored in the database so it would be impossible to have a subsequent step and still be able to submit the information to the payment gateway. Spree submits the information to the gateway before saving the model so that the sensitive information can be discarded before saving the checkout information.
|
|
99
|
-
|
|
100
|
-
Spree stores only the last four digits of the credit card number along with the expiration information. The full credit card number and verification code are never stored in the Spree database.
|
|
101
|
-
|
|
102
|
-
Several gateways such as ActiveMerchant and Beanstream provide a secure method for storing a "payment profile" in your database. This approach typically involves the use of a "token" which can be used for subsequent purchases but only with your merchant account. If you are using a secure payment profile it would then be possible to show a final "confirmation" step after payment information is entered.
|
|
103
|
-
|
|
104
|
-
If you do not want to use a gateway with payment profiles then you will need to customize the checkout process so that your final step submits the credit card information. You can then perform authorization before the order is saved. This is perfectly secure because the credit card information is not ever saved. It's transmitted to the gateway and then discarded like normal.
|
|
105
|
-
|
|
106
|
-
Spree discards the credit card number after this step is processed. If you do not have a gateway with payment profiles enabled then your card information will be lost before it's time to authorize the card.
|
|
107
|
-
|
|
108
|
-
For more information about payments, please see the [Payments guide](../../core-concepts/payments.md).
|
|
109
|
-
|
|
110
|
-
### Confirmation
|
|
111
|
-
|
|
112
|
-
This is the final opportunity for the customer to review their order before submitting it to be processed. Users have the opportunity to return to any step in the process using either the back button or by clicking on the appropriate step in the "progress breadcrumb."
|
|
113
|
-
|
|
114
|
-
This step is disabled by default, but can be enabled by two ways:
|
|
115
|
-
|
|
116
|
-
1. globally for all orders by setting a preference in `config/initializers/spree.rb`:
|
|
117
|
-
|
|
118
|
-
```ruby
|
|
119
|
-
Spree::Config[:always_include_confirm_step] = true
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
2. conditionally for specific orders by overriding the `confirmation_required?` method in `Spree::Order`, eg.
|
|
123
|
-
|
|
124
|
-
```ruby
|
|
125
|
-
module Spree
|
|
126
|
-
module OrderDecorator
|
|
127
|
-
# require confirmation for orders with a US billing address
|
|
128
|
-
def confirmation_required?
|
|
129
|
-
billing_address&.country_iso == 'US'
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Adding Logic Before or After a Particular Step
|
|
136
|
-
|
|
137
|
-
The [state_machines](https://github.com/state-machines/state_machines) gem allows you to implement callbacks before or after transitioning to a particular step. These callbacks work similarly to [Active Record Callbacks](http://guides.rubyonrails.org/active_record_callbacks.html) in that you can specify a method or block of code to be executed prior to or after a transition. If the method executed in a before_transition returns false, then the transition will not execute.
|
|
138
|
-
|
|
139
|
-
So, for example, if you wanted to verify that the user provides a valid zip code before transitioning to the delivery step, you would first implement a `valid_zip_code?` method, and then tell the state machine to run this method before that transition, placing this code in a file called `app/models/spree/order_decorator.rb`:
|
|
140
|
-
|
|
141
|
-
```ruby
|
|
142
|
-
module Spree
|
|
143
|
-
module OrderDecorator
|
|
144
|
-
def self.prepended(base)
|
|
145
|
-
base.state_machine.before_transition to: :delivery, do: :valid_zip_code?
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def valid_zip_code?
|
|
149
|
-
# logic to check if the zip code is valid
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
Order.prepend(OrderDecorator)
|
|
154
|
-
end
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
This callback would prevent transitioning to the `delivery` step if `valid_zip_code?` returns false.
|
|
158
|
-
|
|
159
|
-
## Modifying the checkout flow
|
|
160
|
-
|
|
161
|
-
To add or remove steps to the checkout flow, you can use the
|
|
162
|
-
[insert_checkout_step](https://github.com/spree/spree/blob/a39ed2b69f1f2b2f413b7f46090bd0deeb439d61/core/app/models/spree/order/checkout.rb#L138) and [remove_checkout_step](https://github.com/spree/spree/blob/a39ed2b69f1f2b2f413b7f46090bd0deeb439d61/core/app/models/spree/order/checkout.rb#L157) helpers respectively.
|
|
163
|
-
|
|
164
|
-
The `insert_checkout_step` method takes a `before` or `after` option to determine where to insert the step:
|
|
165
|
-
|
|
166
|
-
```ruby
|
|
167
|
-
module Spree
|
|
168
|
-
module OrderDecorator
|
|
169
|
-
def self.prepended(base)
|
|
170
|
-
base.insert_checkout_step :new_step, before: :address
|
|
171
|
-
# or
|
|
172
|
-
# base.insert_checkout_step :new_step, after: :address
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
Order.prepend(OrderDecorator)
|
|
177
|
-
end
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
The `remove_checkout_step` will remove just one checkout step at a time:
|
|
181
|
-
|
|
182
|
-
```ruby
|
|
183
|
-
module Spree
|
|
184
|
-
module OrderDecorator
|
|
185
|
-
def self.prepended(base)
|
|
186
|
-
base.remove_checkout_step :address
|
|
187
|
-
base.remove_checkout_step :delivery
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
Order.prepend(OrderDecorator)
|
|
192
|
-
end
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
What will happen here is that when a user goes to checkout, they will be asked to potentially fill in their payment details and then potentially confirm the order. This is the default behavior of the payment and the confirm steps within the checkout. If they are not required to provide payment or confirmation for this order then checking out this order will result in its immediate completion.
|
|
196
|
-
|
|
197
|
-
To completely re-define the flow of the checkout, use the `checkout_flow` helper:
|
|
198
|
-
|
|
199
|
-
```ruby
|
|
200
|
-
module Spree
|
|
201
|
-
module OrderDecorator
|
|
202
|
-
def self.prepended(base)
|
|
203
|
-
base.checkout_flow do
|
|
204
|
-
go_to_state :payment
|
|
205
|
-
go_to_state :complete
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
Order.prepend(OrderDecorator)
|
|
211
|
-
end
|
|
212
|
-
```
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Deface Overrides
|
|
3
|
-
version: v4
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
> **WARNING:** Using Deface is no longer recommended, we strongly encourage you to use other ways to customize Spree.
|
|
7
|
-
|
|
8
|
-
## What is Deface?
|
|
9
|
-
|
|
10
|
-
Deface is a standalone Rails library that enables you to customize Erb templates without needing to directly edit the underlying view file. Deface allows you to use standard CSS3 style selectors to target any element including Ruby blocks, and perform an action against all the matching elements.
|
|
11
|
-
|
|
12
|
-
## Improving Our Extension Using Deface
|
|
13
|
-
|
|
14
|
-
### The Goal
|
|
15
|
-
|
|
16
|
-
Our goal is to add a field to the product edit admin page that allows the `sale_price` to be added or updated. We could do this by overriding the view Spree provides, but there are potential problems with this technique. If Spree updates the view in a new release we won't get the updated view as we are already overriding it. We would need to update our view with the new content from Spree and then add our customizations back in to stay fully up to date.
|
|
17
|
-
|
|
18
|
-
Let's do this instead using Deface, which we just learned about. Using Deface will allow us to keep our view customizations in one spot, `app/overrides`, and make sure we are always using the latest implementation of the view provided by Spree.
|
|
19
|
-
|
|
20
|
-
### The Implementation
|
|
21
|
-
|
|
22
|
-
We want to override the product edit admin page, so the view we want to modify in this case is the product form partial. This file's path will be `spree/admin/products/_form.html.erb`.
|
|
23
|
-
|
|
24
|
-
First, let's create the overrides directory with the following command:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
mkdir app/overrides
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
So we want to override `spree/admin/products/_form.html.erb`. Here is the part of the file we are going to add content to you can also view the [full file](https://github.com/spree/spree/blob/main/backend/app/views/spree/admin/products/_form.html.erb):
|
|
31
|
-
|
|
32
|
-
```erb
|
|
33
|
-
<div class="right four columns omega" data-hook="admin_product_form_right">
|
|
34
|
-
<%= f.field_container :price do %>
|
|
35
|
-
<%= f.label :price, raw(Spree.t(:master_price) + required_span_tag) %>
|
|
36
|
-
<%= f.text_field :price, value: number_to_currency(@product.price, unit: '')%>
|
|
37
|
-
<%= f.error_message_on :price %>
|
|
38
|
-
<% end %>
|
|
39
|
-
</div>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
We want our override to insert another field container after the price field container. We can do this by creating a new file `app/overrides/add_sale_price_to_product_edit.rb` and adding the following content:
|
|
43
|
-
|
|
44
|
-
```ruby
|
|
45
|
-
Deface::Override.new(virtual_path: 'spree/admin/products/_form',
|
|
46
|
-
name: 'add_sale_price_to_product_edit',
|
|
47
|
-
insert_after: "erb[loud]:contains('text_field :price')",
|
|
48
|
-
text: "
|
|
49
|
-
<%%= f.field_container :sale_price do %>
|
|
50
|
-
<%%= f.label :sale_price, raw(Spree.t(:sale_price) + content_tag(:span, ' *')) %>
|
|
51
|
-
<%%= f.text_field :sale_price, value:
|
|
52
|
-
number_to_currency(@product.sale_price, unit: '') %>
|
|
53
|
-
<%%= f.error_message_on :sale_price %>
|
|
54
|
-
<%% end %>
|
|
55
|
-
")
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
We also need to delegate `sale_price` to the master variant in order to get the updated product edit form working.
|
|
59
|
-
|
|
60
|
-
We can do this by creating a new file `app/models/spree/product_decorator.rb` and adding the following content to it:
|
|
61
|
-
|
|
62
|
-
```ruby
|
|
63
|
-
module Spree
|
|
64
|
-
Product.class_eval do
|
|
65
|
-
delegate :sale_price, :sale_price=, to: :master
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Now, when we head to `http://localhost:3000/admin/products` and edit a product, we should be able to set a sale price for the product and be able to view it on our sale page, `http://localhost:3000/sale`. Note that you will likely need to restart our example Spree application created in the [Getting Started tutorial](../../getting-started/quickstart.md).
|
|
71
|
-
|
|
72
|
-
### Available actions
|
|
73
|
-
|
|
74
|
-
Deface applies an **action** to elements matching the supplied CSS selector. These actions are passed when defining a new override are supplied as the key while the CSS selector for the target elements is the value, for example:
|
|
75
|
-
|
|
76
|
-
```ruby
|
|
77
|
-
remove: "p.junk"
|
|
78
|
-
|
|
79
|
-
insert_after: "div#wow p.header"
|
|
80
|
-
|
|
81
|
-
insert_bottom: "ul#giant-list"
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Deface currently supports the following actions:
|
|
85
|
-
|
|
86
|
-
* :remove - Removes all elements that match the supplied selector
|
|
87
|
-
* :replace - Replaces all elements that match the supplied selector, with the content supplied
|
|
88
|
-
* :replace_contents - Replaces the contents of all elements that match the supplied selector
|
|
89
|
-
* :surround - Surrounds all elements that match the supplied selector, expects replacement markup to contain <%%= render_original %> placeholder
|
|
90
|
-
* :surround_contents - Surrounds the contents of all elements that match the supplied selector, expects replacement markup to contain <%%= render_original %> placeholder
|
|
91
|
-
* :insert_after - Inserts after all elements that match the supplied selector
|
|
92
|
-
* :insert_before - Inserts before all elements that match the supplied selector
|
|
93
|
-
* :insert_top - Inserts inside all elements that match the supplied selector, as the first child
|
|
94
|
-
* :insert_bottom - Inserts inside all elements that match the supplied selector, as the last child
|
|
95
|
-
* :set_attributes - Sets attributes on all elements that match the supplied selector, replacing existing attribute value if present or adding if not. Expects :attributes option to be passed.
|
|
96
|
-
* :add_to_attributes - Appends value to attributes on all elements that match the supplied selector, adds attribute if not present. Expects :attributes option to be passed.
|
|
97
|
-
* :remove_from_attributes - Removes value from attributes on all elements that match the supplied selector. Expects :attributes option to be passed.
|
|
98
|
-
|
|
99
|
-
Not all actions are applicable to all elements. For example, \`:insert_top\` and \`:insert_bottom\` expects a parent element with children.
|
|
100
|
-
|
|
101
|
-
### Supplying content
|
|
102
|
-
|
|
103
|
-
Deface supports three options for supplying content to be used by an override:
|
|
104
|
-
|
|
105
|
-
* :text - String containing markup
|
|
106
|
-
* :partial - Relative path to a partial
|
|
107
|
-
* :template - Relative path to a template
|
|
108
|
-
|
|
109
|
-
As Deface operates on the Erb source the content supplied to an override can include Erb, it is not limited to just HTML. You also have access to all variables accessible in the original Erb context.
|
|
110
|
-
|
|
111
|
-
### Targeting elements
|
|
112
|
-
|
|
113
|
-
While Deface allows you to use a large subset of CSS3 style selectors as provided by Nokogiri, the majority of Spree's views have been updated to include a custom HTML attribute data-hook, which is designed to provide consistent targets for your overrides to use.
|
|
114
|
-
|
|
115
|
-
As Spree views are changed over coming versions, the original HTML elements maybe edited or be removed. We will endeavour to ensure that data-hook / id combination will remain consistent within any single view file where possible, thus making your overrides more robust and upgrade proof.
|
|
116
|
-
|
|
117
|
-
For example, spree/products/show.html.erb looks as follows:
|
|
118
|
-
|
|
119
|
-
```erb
|
|
120
|
-
<div data-hook="product_show" itemscope itemtype="http://schema.org/Product">
|
|
121
|
-
<%% body_id = 'product-details' %>
|
|
122
|
-
<div class="columns six alpha" data-hook="product_left_part">
|
|
123
|
-
<div class="row" data-hook="product_left_part_wrap">
|
|
124
|
-
<div id="product-images" data-hook="product_images">
|
|
125
|
-
<div id="main-image" data-hook>
|
|
126
|
-
<%%= render 'image' %>
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
<div id="thumbnails" data-hook>
|
|
130
|
-
<%%= render 'thumbnails', product: product %>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
<div data-hook="product_properties">
|
|
135
|
-
<%%= render 'properties' %>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
|
|
141
|
-
<div class="columns ten omega" data-hook="product_right_part">
|
|
142
|
-
<div class="row" data-hook="product_right_part_wrap">
|
|
143
|
-
|
|
144
|
-
<div id="product-description" data-hook="product_description">
|
|
145
|
-
|
|
146
|
-
<h1 class="product-title" itemprop="name"><%%= accurate_title %></h1>
|
|
147
|
-
|
|
148
|
-
<div itemprop="description" data-hook="description">
|
|
149
|
-
<%%= product_description(product) rescue Spree.t(:product_has_no_description) %>
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<div id="cart-form" data-hook="cart_form">
|
|
153
|
-
<%%= render 'cart_form' %>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<%%= render 'taxons' %>
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
As you can see from the example above the `data-hook` can be present in a number of ways:
|
|
164
|
-
|
|
165
|
-
* On elements with **no** `id` attribute the `data-hook` attribute
|
|
166
|
-
|
|
167
|
-
contains a value similar to what would be included in the `id`
|
|
168
|
-
|
|
169
|
-
attribute.
|
|
170
|
-
|
|
171
|
-
* On elements with an `id` attribute the `data-hook` attribute does
|
|
172
|
-
|
|
173
|
-
**not** normally contain a value.
|
|
174
|
-
|
|
175
|
-
* Occasionally on elements with an `id` attribute the `data-hook` will
|
|
176
|
-
|
|
177
|
-
contain a value different from the elements id. This is generally to
|
|
178
|
-
|
|
179
|
-
support migration from the old 0.60.x style of hooks, where the old
|
|
180
|
-
|
|
181
|
-
hook names were converted into `data-hook` versions.
|
|
182
|
-
|
|
183
|
-
The suggested way to target an element is to use the `data-hook` attribute wherever possible. Here are a few examples based on **products/show.html.erb** above:
|
|
184
|
-
|
|
185
|
-
```ruby
|
|
186
|
-
replace: "[data-hook='product_show']"
|
|
187
|
-
|
|
188
|
-
insert_top: "#thumbnails[data-hook]"
|
|
189
|
-
|
|
190
|
-
remove: "[data-hook='cart_form']"
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
You can also use a combination of both styles of selectors in a single override to ensure maximum protection against changes:
|
|
194
|
-
|
|
195
|
-
```ruby
|
|
196
|
-
insert_top: "[data-hook='thumbnails'], #thumbnails[data-hook]"
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Targeting ruby blocks
|
|
200
|
-
|
|
201
|
-
Deface evaluates all the selectors passed against the original erb view contents and importantly not against the finished / generated HTML. In order for Deface to make ruby blocks contained in a view parseable they are converted into a pseudo markup as follows.
|
|
202
|
-
|
|
203
|
-
Given the following Erb file:
|
|
204
|
-
|
|
205
|
-
```erb
|
|
206
|
-
<%% if products.empty? %>
|
|
207
|
-
<%%= Spree.t(:no_products_found) %>
|
|
208
|
-
<%% elsif params.key?(:keywords) %>
|
|
209
|
-
<h3><%%= Spree.t(:products) %></h3>
|
|
210
|
-
<%% end %>
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Would be seen by Deface as:
|
|
214
|
-
|
|
215
|
-
```markup
|
|
216
|
-
<!-- <html>
|
|
217
|
-
<erb[silent]> if products.empty? </erb>
|
|
218
|
-
<erb[loud]> Spree.t(:no_products_found) </erb>
|
|
219
|
-
<erb[silent]> elsif params.key?(:keywords) </erb>
|
|
220
|
-
|
|
221
|
-
<h3><erb[loud]> Spree.t(:products) </erb></h3>
|
|
222
|
-
|
|
223
|
-
<erb[silent]> end </erb>
|
|
224
|
-
</html> -->
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
So you can target ruby code blocks with the same standard CSS3 style selectors, for example:
|
|
228
|
-
|
|
229
|
-
```ruby
|
|
230
|
-
replace: "erb[loud]:contains('t(:products)')"
|
|
231
|
-
|
|
232
|
-
insert_before: "erb[silent]:contains('elsif')"
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### View upgrade protection
|
|
236
|
-
|
|
237
|
-
To ensure upgrading between versions of Spree is as painless as possible, Deface supports an `:original` option that can contain a string of the original content that's being replaced. When Deface is applying the override it will ensure that the current source matches the value supplied and will output to the Rails application log if they are different.
|
|
238
|
-
|
|
239
|
-
These warnings are a good indicator that you need to review the source and ensure your replacement is adequately replacing all the functionality provided by Spree. This will help reduce unexpected issues after upgrades.
|
|
240
|
-
|
|
241
|
-
Once you've reviewed the new source you can update the `:original` value to new source to clear the warning.
|
|
242
|
-
|
|
243
|
-
Deface removes all whitespace from both the actual and \`:original\` source values before comparing, to reduce false warnings caused by basic whitespace differences.
|
|
244
|
-
|
|
245
|
-
### Organizing Overrides
|
|
246
|
-
|
|
247
|
-
The suggested method for organizing your overrides is to create a separate file for each override inside the **app/overrides** directory, naming each file the same as the **:name** specified within.
|
|
248
|
-
|
|
249
|
-
### More information on Deface
|
|
250
|
-
|
|
251
|
-
For more information and sample overrides please refer to its [README](https://github.com/spree/deface) file on GitHub.
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Images
|
|
3
|
-
version: v4
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This guide explains how to change Product Images dimensions and different storage options for [ActiveStorage](https://edgeguides.rubyonrails.org/active_storage_overview.html) which is the default attachment storage system in Spree.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Dimensions
|
|
12
|
-
|
|
13
|
-
To change the default image dimensions or add new ones you need to create a decorator file:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
mkdir -p app/models/spree && touch app/models/spree/image_decorator.rb
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
with the following content:
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
module Spree
|
|
23
|
-
module ImageDecorator
|
|
24
|
-
module ClassMethods
|
|
25
|
-
def styles
|
|
26
|
-
{
|
|
27
|
-
# change existing default sizes used in Admin Panel and API
|
|
28
|
-
mini: '48x48>',
|
|
29
|
-
small: '100x100>',
|
|
30
|
-
product: '240x240>',
|
|
31
|
-
large: '600x600>',
|
|
32
|
-
# add your new size here, which will be automatically available in the API
|
|
33
|
-
my_custom_size: '1000x1000>'
|
|
34
|
-
}
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.prepended(base)
|
|
39
|
-
base.inheritance_column = nil
|
|
40
|
-
base.singleton_class.prepend ClassMethods
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
Image.prepend(ImageDecorator)
|
|
45
|
-
end
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Using image variations in templates
|
|
49
|
-
|
|
50
|
-
You can also create [image variations on the fly in your templates](https://guides.rubyonrails.org/active_storage_overview.html), eg.
|
|
51
|
-
|
|
52
|
-
```erb
|
|
53
|
-
<%= image_tag(main_app.url_for(@product.images.first.attachment.variant(resize: '150x150'))) %>
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Storage service
|
|
57
|
-
|
|
58
|
-
By default Spree will use the storage service you have set in your environment file eg. `config/environments/development.rb`:
|
|
59
|
-
|
|
60
|
-
```ruby
|
|
61
|
-
config.active_storage.service = :amazon
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
If you have multiple storage services you can customize which storage service to use for images. This is done in the `config/initializers/spree.rb`:
|
|
65
|
-
|
|
66
|
-
```ruby
|
|
67
|
-
Spree.public_storage_service_name = :amazon
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
The storage name needs to match the name you configured in `config/storage.yml`.
|
|
71
|
-
|
|
72
|
-
## Using CDNs
|
|
73
|
-
|
|
74
|
-
To use a CDN service such as AWS Cloudfront or Cloudflare, you need to set `Spree.cdn_host` to the hostname of your CDN service. This is done in the `config/initializers/spree.rb`:
|
|
75
|
-
|
|
76
|
-
```ruby
|
|
77
|
-
Spree.cdn_host = 'https://mycloudfrontserviceid.cloudfront.net'
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Spree will handle the rest as we have a built-in reverse proxy for ActiveStorage.
|
|
81
|
-
|
|
82
|
-
To use CDN in your templates please use `cdn_image_url` helper:
|
|
83
|
-
|
|
84
|
-
```erb
|
|
85
|
-
<%= main_app.cdn_image_url(@product.images.first.attachment.variant(resize: '150x150')) %>
|
|
86
|
-
```
|