Online marketplace step by step.
- Подготовка рабочей среды
- Выбор версии Rails
- Использование rbenv
- Создание Rails-приложения
- Файловая структура Rails-приложения
- Соглашение по именованию
- Диагностическая информация
- Создание Spree e-commerce платформы
- Миграция с Sqlite3 → Postgres
- Добавление расширений Spree
- Создание собственных расширений Spree
- Работа с Deface
- Настройка Spree
- FAQ
См. также:
docs/rails
— введение в Rails.docs/ruby
— введение в Ruby.docs/rake
— введение в Rake.docs/postgres
— работа с Postgres.docs/react
— руководство по переходу и работе с React.js.docs/problems
— проблемы и решения.
-
Проверьте все установленные версии Rails:
$ gem list --local rails
-
Проверьте какая версия Rails запускается по умолчанию:
rails --version
-
Установите необходимую версию Rails:
$ rvm gemset empty $ rvm gemset create $ gem install rails -v '5.2.0'
# As an rbenv plugin
$ rbenv install --list # lists all available versions of Ruby
$ rbenv install 2.5.0 # installs Ruby 2.5.0 to ~/.rbenv/versions
$ rbenv global 2.5.0 # Activate Ruby 2.5.0
# As a standalone program
$ ruby-build --definitions # lists all available versions of Ruby
$ ruby-build 2.5.0 ~/local/ruby-2.5.0 # installs Ruby 2.5.0 to ~/local/ruby-2.5.0
Примечание. Spree зависит от определенной версии Rails. Подробно о нужной версии можно узнать из документации.
Чтобы создать приложение, выполните команду:
$ rails new marketplace
Приложение успешно создано. Перейдите в директорию spree-marketplace
и запустите сервер.
$ cd spree-marketplace
$ rails server
Примечание. При запуске приложения в терминале выведится сообщение о том, что сервер выполняется на порте 3000. Откройте браузер и введите адрес localhost:3000.
Чтобы запустить сервер на другом порту (например, 9000), выполните команду:
$ rails server -p 9000
Ответ
Примечание. По умолчанию Rails использует сервер WEBrick. Но если на машинке установлен другой веб-сервер (и Rails может его найти), команда rails server может предпочесть его серверу WEBrick.
app/ # Модели, представления, контроллеры и статика
assets/ # Картинки, JS- и CSS-файлы приложения
config/
manifest.js
images/ # Изображения
javascript/ # JS-файлы, по умолчанию `coffee`
stylesheets/ # Стили, по умолчанию `scss`
channels/
controllers/
helpers/
jobs/
mailers/
models/
views/
layouts/
application.html.erb # Макет приложения
mailer.html.erb # Макет письма для отправки
mailer.text.erb # Шаблон текста письма
bin # Rails-скрипты для старта приложения
config # Конфигурации маршрутов, базы данных приложения
database.yml # [YAML]( http://www.yaml.org/)-конфигурация базы данных приложения
boot.rb # Сценарий начальной загрузки приложения (редактировать его не стоит)
environment.rb # Файл в котором определяются параметры запуска приложения
db # Схема данных и информация о миграции
migrate/ # Файлы миграции
schema.rb # Текущая схема базы данных SQLite 3
seeds.rb # Файл помогает импортировать исходные данные в базу данных
lib # Общий код не связынный с контроллерами, моделями и представлениями. Например, код, генерирующий чеки, документацию для отправки заказа покупателю и другие документы в формате PDF. Подкаталоги можно группировать по своему назначению.
assets/
tasks/ # Собственные Rack-задачи, позволяющие добавлять автоматику к проекту
log # Файлы логов (протоколов)
public # Каталог доступный из интернета, откуда запускается приложение
test # Юнит-тесты
tmp # Временные файлы: подкаталоги для кэш-содержимого, сессий и сокетов
vendor # Внешние gem'ы, aka node_modules
rails/ # Этой директории нет, но если будет желание пересесть на «Острие Rails», то можно скачать сюда необходимую версию и выполнить заморозку проекта к конкретной версии: `rails:freeze:edge` и `rails:unfreeze`. Сейчас в этом совсем нет необходимости.
config.ru # Конфигурация Rack-сервера
Gemfile # Gem-зависимости
Gemfile.lock # Записи о конкретных версиях каждого пакета
package.json # npm-зависимости
Rakefile # Задачи, которые могут быть запущены в командной строке. Полный список задач: rake -T, описание конкретной задачи: rake -D задача
README.md # Описание
В предыдущих версиях Rails файлы в каталоге lib
автоматически включались в путь загрузки, используемый для выполнения инструкций require Теперь это элемент настройки, который нужно включить явным образом. Для этого в файл config/application.rb
следует включить строку:
config.autoload_paths += %W(#{Rails.root}/lib)
Когда у вас будут файлы в каталоге lib
и этот каталог будет добавлен в ваши пути автозагрузки (autoload_paths), вы сможете ими воспользоваться во всем остальном приложении. Если файлы содержат классы или модули и файлы названы с использованием имени класса или модуля в форме букв нижнего разряда, тогда Rails загрузит такой файл автоматически. Например, у нас может быть составитель чека в формате PDF, который находится в файле receipt.rb
в каталоге lib/pdf_stuff
.
Если только наш класс носит имя PdfStuff::Receipt
, Rails сможет найти и загрузить его автоматически. Для тех случаев, когда библиотека не может отвечать условиям автоматической загрузки, необходимо использовать имеющийся в Ruby механизм запроса, использующий инструкцию require
. Если файл находится в каталоге lib
, его можно запрашивать непосредственно по имени. Например, если наша библиотека вычисления дня Пасхи находится в файле lib/easter.rb
, мы можем включить ее в любую модель, представление или контроллер, используя следующую инструкцию:
require "easter"
Если библиотека находится в подкаталоге каталога lib
, нужно не забыть включить имя этого подкаталога в инструкцию require
. Например, для включения калькулятора доставки авиапочтой можно добавить следующую строку кода:
require "shipping/airmail"
В Ruby применяется соглашение, при котором имена переменных пишутся в нижнем регистре, а слова разделяются знаком подчеркивания. Классы и модули именуются по-другому: в их именах не используется знак подчеркивания, а каждое слово фразы (включая первое) пишется с заглавной буквы.
Пример
Класс LineItem
определяется в файле с именем line_item.rb
, в каталоге app/models
.
На основе этого имени Rails автоматически придет к следующему заключению: соответствующая таблица базы данных будет названа line_items
(во множественном числе).
Контроллеры Rails имеют дополнительные соглашения об именах. Если в нашем приложении есть контроллер store
, происходит следующее:
- Rails предполагает, что класс называется
StoreController
и находится в файлеstore_controller.rb
каталогаapp/controllers
. - Rails также ищет вспомогательный модуль по имени
StoreHelper
, который находится в файлеstore_helper.rb
каталогаapp/helpers
. - Rails станет искать шаблоны представлений для этого контроллера в каталоге
app/views/store
. - Rails будет по умолчанию брать код вывода на экран для этих представлений и рассматривать его как макеты шаблонов, находящихся в файле
store.html.erb
илиstore.xml.erb
в каталогеapp/views/layouts
.
Все эти соглашения показаны в следующей таблице:
Чтобы увидеть на экране диагностическую информацию о приложении, запустите сервер и перейдите по ссылке http://localhost:3000/rails/info/properties.
Чтобы добавить Spree:
-
Перейдите в директорию проекта.
$ cd spree-marketplace
-
Добавьте gem'ы в Gemfile. Подробно о нужных версиях gem'ов можно узнать из документации. Текущие gem'ы используются для Rails 5.2.
gem 'spree', '~> 3.6.3' gem 'spree_auth_devise', '~> 3.3' gem 'spree_gateway', '~> 3.3'
-
Устанавите добавленные gem'ы.
$ bundle install
Примечание. Чтобы обновить установленные ранее gem'ы, выполните команду
bundle update
. Чтобы увидеть куда gem был установлен, выполните команду:bundle info [gemname]
. -
Запустите установщик Spree.
$ rails generate spree:install --user_class=Spree::User $ rails generate spree:auth:install $ rails generate spree_gateway:install
-
Запускаем сервер.
$ rails server
При запуске приложения в терминале выведится сообщение о том, что сервер выполняется на порте 3000. Откройте браузер и введите адрес localhost:3000.
Примечание. Если порт 3000 занят, его можно переназначить (например, на 9000).
$ rails server -p 9000
По умолчанию Spree настроен на работу с базой данных Sqlite3. Она отлично подходит для демонстрации тестового проекта, но не для продакшн marketplace.
Чтобы настроить Rails-приложение на работу с MySQL, Oracle, Postgres или SQL Server, необходимо установить одну из бублиотек, которую Rails сможет использовать для подключения и взаимодействия с базой данных.
Библиотеки:
- MySQL — mysql-ruby.
- Oracle — ruby-oci8.
- Postgres — pg.
- SQL Server — rails-sqlserver.
У каждой из этих БД есть свои плюсы и минусы. Для нашего marketplace мы выбрали PostgreSQL.
Чтобы выполнить миграцию Sqlite3 → Postgres:
- Установите библиотеку pg.
- Создайте базы данных.
- Настройте приложение на работу с Postgres
- Выполните миграцию Sqlite3 → Postgres
Pg — это библиотека Ruby, которая представляет интуитивный веб-интерфейс для управления базами данных PostgreSQL.
Примечание. Версия
pg
очень важна.
Первый способ
Чтобы установить pg
, выполните команду:
$ gem install pg -v 0.18.4
Второй способ
-
Добавьте бублиотеку
pg
в Gemfile:$ gem 'pg', '~> 0.18.4'
-
Установите добавленный gem.
$ bundle install
Создадим следующие базы данных:
spreemarketplacedev
— для разработки;spreemarketplacetest
— для тестирования;spreemarketplaceprod
— для продакшн.
Чтобы создать базы данных:
-
Войдите в Postgres.
$ psql
-
Выполните следующие команды:
CREATE DATABASE spreemarketplacedev; CREATE DATABASE spreemarketplacetest; CREATE DATABASE spreemarketplaceprod;
Отредактируйте файл /config/database.yml:
# Postgres
# gem install pg
#
# Ensure the Postgres gem is defined in your Gemfile
# gem 'pg', '~> 0.18'
#
default: &default
adapter: postgresql
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
encoding: utf8
timeout: 5000
development:
<<: *default
host: localhost
database: spreemarketplacedev
username: godfreyd
password: ss$0psrc*
test:
<<: *default
database: spreemarketplacetest
username: godfreyd
password: ss$0psrc*
production:
<<: *default
database: spreemarketplaceprod
username: godfreyd
password: ss$0psrc*
Важно! При использовании табов может возникать синтаксическая ошибка.
Чтобы смигрировать с Sqlite3 на Postgres, выполните команду:
$ rake db:migrate
Готово! Миграция выполнена. Перейдите в директорию spree-marketplace
и запустите сервер.
$ cd spree-marketplace
$ rails server
Проверка приложения:
При запуске приложения в терминале выведится сообщение о том, что сервер выполняется на порте 3000. Откройте браузер и введите адрес localhost:3000.
Проверка админки:
Перейдите по адресу localhost:3000/admin и ведите e-mail: [email protected]
и пароль: spree123
.
Примечание. Если вы не использовали параметр
--auto-accept
при добавлении Spree в приложение Rails и не установили исходные данные, пользовательadmin
не будет существовать в вашей базе данных.
Чтобы создать нового администратора, выполните команду:
$ rake spree_auth:admin:create
Чтобы установить SpreeI18n:
-
Добавьте gem в Gemfile.
gem 'spree_i18n', github: 'spree-contrib/spree_i18n', branch: 'master'
-
Устанавите добавленный gem.
$ bundle install
-
Запустите установщик Spree.
$ bundle exec rails g spree_i18n:install
Добавление дополнительной функциональности в Spree реализуется через расширения, которые затем встраиваются в приложение.
Важно! Расширения создаются вне самого приложения Spree.
Создайте директорию spree-extensions
, для удобства разработки расширений.
$ mkdir spree-extensions
Давайте создадим расширение simple_sales
, чтобы иметь возможность назначать скидку на определенные товары.
- Создание шаблона расширения
- Создание миграции
- Установка расширения
- Создание контроллера
- Добавление скидки товару
- Создание представления
- Переопределение представления Spree
- Тестирование расширения
-
Перейдите в директорию
spree-extensions
.$ cd spree-extensions
-
Выполните команду:
$ spree extension simple_sales
Примечание. Эта команда создаст каталог
spree_simple_sales
с необходимыми файлами и каталогами.
Шаблон расширения готов!
Первое, что необходимо сделать — создать миграцию в БД, которая добавит столбец sale_price
к таблице с вариантами. Вариантами в Spree называют индивидуальные/изменяемые свойства продукта, такие как высота, ширина, глубина и себестоимость. Подробнее про свойства продукта.
Чтобы создать миграцию в БД:
-
Перейдите в директорию созданного расширения.
$ cd spree_simple_sales
-
Выполните команду:
$ bundle install $ bundle exec rails g migration add_sale_price_to_spree_variants sale_price:decimal
Ответ
Running via Spring preloader in process 5327 invoke active_record create db/migrate/20180612131103_add_sale_price_to_spree_variants.rb
-
Отредактируйте файл
db/migrate/XXXXXXXXXXX_add_sale_price_to_spree_variants.rb
, чтобы обеспечить точность и масштаб:class AddSalePriceToSpreeVariants < SpreeExtension::Migration[5.2] def change add_column :spree_variants, :sale_price, :decimal, precision: 8, scale: 2 end end
Примечание. Измените наследование от
ActiveRecord:: Migration
наSpree::Migration
для поддержки нескольких версий Rails.
Миграция готова!
Чтобы установить расширение:
-
Перейдите в директорию проекта.
$ cd spree-marketplace
-
Добавьте gem расширения
spree_simple_sales
в Gemfile приложения.gem 'spree_simple_sales', path: '../spree-extensions/spree_simple_sales'
-
Выполните команду:
$ bundle install
-
Запустите установщик Spree, чтобы скопировать миграцию, которую мы создали (ответьте «Да», если будет предложено запустить миграцию).
$ rails g spree_simple_sales:install
Ответ:
Расширение spree_simple_sales
установлено!
Добавим событие в Spree::HomeController
, по которому будут выбираться товары со скидками.
-
Перейдите в директорию расширения
spree_simple_sales
.$ cd spree_simple_sales
-
Выполните команду:
$ mkdir -p app/controllers/spree
-
Создайде файл
app/controllers/spree/home_controller_decorator.rb
. -
Добавьте в файл
home_controller_decorator.rb
следующий код:Spree::HomeController.class_eval do def sale @products = Spree::Product.joins(:variants_including_master).where('spree_variants.sale_price is not null').distinct end end
Примечание. Это позволит выбрать только те продукты, которые имеют вариант с набором
sale_price
.
-
Добавьте маршрут к этому действию в файл
config/routes.rb
.Spree::Core::Engine.routes.draw do get "/sale" => "home#sale" end
Контроллер готов!
Чтобы добавить скидку товару:
-
Перейдите в директорию проекта.
$ cd spree-marketplace
-
Перейдите в Rails-консоль:
$ rails console
Примечание. Добавить скидку можно через панель администратора. Это мы рассмотрим позже.
-
Выполните следующие действия (в примере мы выставляем скидку 8 продукту с
id
равным 1):> product = Spree::Product.first => #<Spree::Product id: 1, name: "Ruby on Rails Tote", description: "Quae est vitae minus maxime veniam distinctio. Per...", available_on: "2018-06-12 12:57:53", deleted_at: nil, slug: "ruby-on-rails-tote", meta_description: nil, meta_keywords: nil, tax_category_id: 1, shipping_category_id: 1, created_at: "2018-06-12 12:57:53", updated_at: "2018-06-12 12:59:02", promotionable: true, meta_title: nil, discontinue_on: nil> > variant = product.master => #<Spree::Variant id: 1, sku: "ROR-00011", weight: 0.0, height: nil, width: nil, depth: nil, deleted_at: nil, is_master: true, product_id: 1, cost_price: 0.17e2, position: 1, cost_currency: "USD", track_inventory: true, tax_category_id: nil, updated_at: "2018-06-12 12:59:02", discontinue_on: nil, created_at: "2018-06-12 12:57:53", sale_price: nil> > variant.sale_price = 8.00 => 8.0 > variant.save => true > exit
Товару с id
= 1 добавлена скидка = 8.0!
Чтобы отобразить товары со скидкой:
-
Перейдите в директорию расширения
spree_simple_sales
.$ cd spree_simple_sales
-
Выполните команду:
$ mkdir -p app/views/spree/home
-
Создайте файл
app/views/spree/home/sale.html.erb
. -
Добавьте в него следующий код:
<div data-hook="homepage_products"> <%= render 'spree/shared/products', products: @products %> </div>
Представление готово! Чтобы убедиться, что контроллер отвечает, запустите приложение и перейдите по адресу localhost:3000/sale.
Давайте переопределим отображение цены в расширение так, чтобы оно использовало sale_price
, когда sale_price
присутствует у товара. Все действия необходимо выполнять в директории расширения, чтобы не потерять возможность обновлять Spree.
-
Перейдите в директорию расширения
spree_simple_sales
.$ cd spree_simple_sales
-
Создайте необходимые каталоги.
$ mkdir -p app/models/spree
-
Создайте файл
app/models/spree/variant_decorator.rb
. -
Добавьте в него следующее содержимое:
Spree::Variant.class_eval do alias_method :orig_price_in, :price_in def price_in(currency) return orig_price_in(currency) unless sale_price.present? Spree::Price.new(variant_id: self.id, amount: self.sale_price, currency: currency) end end
Должна отображаться цена скидки!
Напишем несколько модульных тестов для app/models/spree/variant_decorator.rb
-
Перейдите в директорию расширения
spree_simple_sales
.$ cd spree_simple_sales
-
Выполните команду:
$ bundle exec rake test_app
Ответ
No examples found. Finished in 0.00005 seconds 0 examples, 0 failures
Чтобы создать тест:
-
Создайте необходимые каталоги:
$ mkdir -p spec/models/spree
-
Создайте файл
spec/models/spreevariant_decorator_spec.rb
-
Добавьте в
spreevariant_decorator_spec.rb
следующий код:require 'spec_helper' describe Spree::Variant do describe "#price_in" do it "returns the sale price if it is present" do variant = create(:variant, sale_price: 8.00) expected = Spree::Price.new(variant_id: variant.id, currency: "USD", amount: variant.sale_price) result = variant.price_in("USD") expect(result.variant_id).to eq(expected.variant_id) expect(result.amount.to_f).to eq(expected.amount.to_f) expect(result.currency).to eq(expected.currency) end it "returns the normal price if it is not on sale" do variant = create(:variant, price: 15.00) expected = Spree::Price.new(variant_id: variant.id, currency: "USD", amount: variant.price) result = variant.price_in("USD") expect(result.variant_id).to eq(expected.variant_id) expect(result.amount.to_f).to eq(expected.amount.to_f) expect(result.currency).to eq(expected.currency) end end end
-
Заново выполните команду в корневом каталоге расширения:
$ bundle exec rake test_app
[Deface](https://github.co m/spree/deface) — это библиотека Rails, позволяющая переопределять Erb-шаблоны без их непосредственного редактирования. Таким образом, мы получим возможность обновлять Spree, не теряя наши изменения.
Цель:
Переопределить шаблон spree/admin/products/_form.html.erb, точнее следующую часть.
Чтобы переопределить нативный шаблон Spree:
-
Добавьте директорию:
app/overrides
.$ mkdir app/overrides
-
Создайте файл
app/overrides/add_sale_price_to_product_edit.rb
. -
Добавьте в созданный файл следующий контент:
Deface::Override.new(virtual_path: 'spree/admin/products/_form', name: 'add_sale_price_to_product_edit', insert_after: "erb[loud]:contains('text_field :price')", text: " <%= f.field_container :sale_price do %> <%= f.label :sale_price, raw(Spree.t(:sale_price) + content_tag(:span, ' *')) %> <%= f.text_field :sale_price, value: number_to_currency(@product.sale_price, unit: '') %> <%= f.error_message_on :sale_price %> <% end %> ")
-
Добавьте
sale_price
в master variant, чтобы получить обновленную форму редактирования продукта. Для этого создайте файлapp/models/spree/product_decorator.rb
и добавьте в него следующий контент:module Spree Product.class_eval do delegate :sale_price, :sale_price=, to: :master end end
-
Откройте браузер и введите адрес localhost:3000/admin/products.
-
Установите цену скидки на любой из товаров.
-
Проверьте результат localhost:3000/sale.
Все работает, супер!
Чтобы повысить производительность приложения:
-
Выключите режим поддержки активных соединений (нужен только в продакшн).
Примечание. Rails 3.1 представила концепцию поддержки активных соединений
assets:pipeline
. При разработке данную возможность можно отключить, чтобы повысить производительность приложения.$ bundle exec rake assets:precompile
-
Очистите каталог
public/assets
.$ bundle exec rake assets:clean
-
Добавьте каталог
public/assets
в файл .gitignore.
- Как посмотреть какие у нас есть пути в приложении?
- Как зайти в админку?
- Как отключить диспетчер Rails для production и testing?
- Как управлять пользователями в Mac OS?
Выполните команду (первый сопособ):
$ rake routes
Перейдите по адресу (второй способ):
localhost:3000/rails/info/routes
-
Запустите сервер:
$ rails server
-
Войдите в админку localhost:3000/admin.
Примечание. Username:
[email protected]
, password:spree123
.
См. главу 16 «Задача: развертывание и эксплуатация», Rails 4. Гибкая разработка web-приложений.
Чтобы создать пользователя (например, postgres
), введите команду:
$ sudo adduser postgres
Чтобы удалить пользователя (например, postgres
), введите команду:
$ sudo deluser postgres
Чтобы изменить пароль существующему пользователю (например, postgres
), введите команду:
$ sudo passwd postgres
Чтобы изменить текущего пользователя сеанса (например, с godfreyd@213:~
на postgres
), введите команду:
$ su postgres
Примечание. Потребуется ввести пароль пользователя
postgres
.
==========
https://www.sharetribe.com/academy/what-you-need-to-know-before-starting-your-marketplace-business/ — Гид по созданию Маркетплейса.
https://www.sharetribe.com — https://www.sharetribe.com
https://gorails.com/setup/osx/10.13-high-sierra https://guides.spreecommerce.org/developer/getting_started_tutorial.html https://spreecommerce.org https://github.com/rails/rails https://github.com/rbenv/rbenv http://localhost:3000
==========
Ошибка в devise-4.3.0/app/controllers/devise/sessions_controller.rb:5
Описание heartcombo/devise#4719 (comment) Решение https://github.com/plataformatec/devise/commit/1009096172f2cbc86bcd54d053c89a09be67fb9f
Можно также здесь поправить на 4.4.0 https://github.com/spree/spree_auth_devise/pull/382/files
==========