├── .gitignore
├── .ruby-version
├── Gemfile
├── Procfile
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ └── stylesheets
│ │ └── application.css
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── admin
│ │ └── admins_controller.rb
│ ├── api
│ │ └── vue_controller.rb
│ ├── application_controller.rb
│ ├── concerns
│ │ └── .keep
│ ├── landing_controller.rb
│ ├── sessions_controller.rb
│ └── users_controller.rb
├── helpers
│ ├── application_helper.rb
│ ├── landing_helper.rb
│ ├── sessions_helper.rb
│ └── users_helper.rb
├── javascript
│ ├── additional
│ │ └── nav_responsive.js
│ ├── app.vue
│ ├── channels
│ │ ├── consumer.js
│ │ └── index.js
│ ├── components
│ │ ├── VueComponent.vue
│ │ └── mixins
│ │ │ └── i18n_mixin.js
│ ├── css
│ │ ├── application.css
│ │ ├── carousel.css
│ │ ├── header.css
│ │ └── tailwind.js
│ ├── images
│ │ └── rails_vuejs_tailwindcss.png
│ └── packs
│ │ └── application.js
├── jobs
│ └── application_job.rb
├── mailers
│ └── application_mailer.rb
├── models
│ ├── application_record.rb
│ ├── concerns
│ │ └── .keep
│ └── user.rb
└── views
│ ├── admin
│ └── index.html.erb
│ ├── landing
│ └── index.html.erb
│ ├── layouts
│ ├── _carousel-slider.html.erb
│ ├── _footer.html.erb
│ ├── _header.html.erb
│ ├── _second_component.html.erb
│ ├── admin
│ │ ├── _nav.html.erb
│ │ ├── _sidebar.html.erb
│ │ └── application.html.erb
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ └── users
│ ├── _cabinet_nav.html.erb
│ ├── _login_form.html.erb
│ ├── _registration_form.html.erb
│ ├── index.html.erb
│ ├── login_register.html.erb
│ └── show.html.erb
├── babel.config.js
├── bin
├── bundle
├── rails
├── rake
├── setup
├── spring
├── webpack
├── webpack-dev-server
└── yarn
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── credentials.yml.enc
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── content_security_policy.rb
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── locale.rb
│ ├── mime_types.rb
│ └── wrap_parameters.rb
├── locales
│ ├── en.yml
│ └── ru.yml
├── puma.rb
├── routes.rb
├── spring.rb
├── storage.yml
├── webpack
│ ├── development.js
│ ├── environment.js
│ ├── loaders
│ │ └── vue.js
│ ├── production.js
│ └── test.js
└── webpacker.yml
├── db
├── migrate
│ └── 20190913103805_create_users.rb
├── schema.rb
└── seeds.rb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── log
└── .keep
├── package.json
├── postcss.config.js
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── favicon.ico
├── javascripts
│ ├── i18n.js
│ └── translations.js
└── robots.txt
├── storage
└── .keep
├── test
├── application_system_test_case.rb
├── channels
│ └── application_cable
│ │ └── connection_test.rb
├── controllers
│ ├── .keep
│ ├── landing_controller_test.rb
│ ├── sessions_controller_test.rb
│ └── users_controller_test.rb
├── fixtures
│ ├── .keep
│ ├── files
│ │ └── .keep
│ └── users.yml
├── helpers
│ └── .keep
├── integration
│ └── .keep
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ └── user_test.rb
├── system
│ ├── .keep
│ └── users_test.rb
└── test_helper.rb
├── tmp
└── .keep
└── vendor
└── .keep
/.gitignore:
--------------------------------------------------------------------------------
1 | g# See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore all logfiles and tempfiles.
11 | /log/*
12 | /tmp/*
13 | !/log/.keep
14 | !/tmp/.keep
15 |
16 | # Ignore uploaded files in development.
17 | /storage/*
18 | !/storage/.keep
19 |
20 | /public/assets
21 | .byebug_history
22 |
23 | # Ignore master key for decrypting credentials and more.
24 | /config/master.key
25 |
26 | /public/packs
27 | /public/packs-test
28 | /node_modules
29 | /yarn.lock
30 | /yarn-error.log
31 | yarn-debug.log*
32 | .yarn-integrity
33 | .browserslistrc
34 | /.idea
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.6.5
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | ruby '2.6.5'
5 |
6 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
7 | gem 'rails', '~> 6.0.0'
8 | # Use postgresql as the database for Active Record
9 | gem 'pg', '>= 0.18', '< 2.0'
10 | # Use Puma as the app server
11 | gem 'puma', '~> 3.12'
12 | # Use SCSS for stylesheets
13 | gem 'sass-rails', '~> 5'
14 | # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
15 | gem 'webpacker', '~> 4.0'
16 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
17 | gem 'turbolinks', '~> 5'
18 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
19 | gem 'jbuilder', '~> 2.7'
20 | # Use Redis adapter to run Action Cable in production
21 | # gem 'redis', '~> 4.0'
22 | # Use Active Model has_secure_password
23 | # gem 'bcrypt', '~> 3.1.7'
24 |
25 | # Use Active Storage variant
26 | # gem 'image_processing', '~> 1.2'
27 |
28 | # Reduces boot times through caching; required in config/boot.rb
29 | gem 'bootsnap', '>= 1.4.2', require: false
30 |
31 | group :development, :test do
32 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
33 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
34 | end
35 |
36 | group :development do
37 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
38 | gem 'listen', '>= 3.0.5', '< 3.2'
39 | gem 'web-console', '>= 3.3.0'
40 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
41 | gem 'spring'
42 | gem 'spring-watcher-listen', '~> 2.0.0'
43 | end
44 |
45 | group :test do
46 | # Adds support for Capybara system testing and selenium driver
47 | gem 'capybara', '>= 2.15'
48 | gem 'selenium-webdriver'
49 | # Easy installation and use of web drivers to run system tests with browsers
50 | gem 'webdrivers'
51 | end
52 |
53 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
54 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
55 |
56 | gem 'bcrypt'
57 | gem 'encrypted_form_fields'
58 | gem 'foreman'
59 | gem 'i18n'
60 | gem 'i18n-js'
61 | gem 'jwt_sessions'
62 | gem 'rack-cors'
63 | gem 'sprockets'
64 | gem 'sprockets-rails'
65 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | backend: bin/rails s -p 3000
2 | frontend: bin/webpack-dev-server
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rails + VueJS + Tailwind CSS extended starter kit
2 | 
3 |
4 | Starter kit for Ruby on Rails framework with pre-configured PostgreSQL, VueJS components, Tailwind CSS, FontAwesome icons, Turbolinks, I18n coverage on Rails views and VueJS components.
5 |
6 | Turbolinks works with Rails Views and VueJS components and works with I18n also.
7 |
8 | This starter kit also contains admin side and can be accessed via your_url.example/admin
9 |
10 | Login data can be found in ../db/seeds.rb file.
11 |
12 | 
13 |
14 |
15 | Configure
16 | -------------
17 |
18 |
19 | `$ bundle install`
20 |
21 | `$ yarn install`
22 |
23 | `$ rake db:create`
24 |
25 | `$ rake db:migrate`
26 |
27 | Start server
28 |
29 | `$ foreman start`
30 |
31 | You can deploy via Nginx with follow config:
32 | ```
33 | upstream puma {
34 | server 127.0.0.1:3000;
35 | }
36 | server {
37 | listen 80;
38 | listen [::]:80;
39 | server_name yourdomain.local;
40 | try_files $uri/index.html $uri @puma;
41 | location / {
42 | proxy_set_header X-Forwarded-Proto $scheme;
43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
44 | proxy_set_header X-Real-IP $remote_addr;
45 | proxy_set_header Host $http_host;
46 | proxy_redirect off;
47 | proxy_pass http://puma$request_uri;
48 | }
49 | root .../railspath/public;
50 | location ^~ /assets/ {
51 | gzip_static on;
52 | expires max;
53 | add_header Cache-Control public;
54 | }
55 | location ^~ /system/ {
56 | gzip_static on;
57 | expires max;
58 | add_header Cache-Control public;
59 | }
60 | error_page 500 502 503 504 /500.html;
61 | error_page 404 /404.html;
62 | error_page 422 /422.html;
63 | client_max_body_size 10M;
64 | keepalive_timeout 10;
65 | }
66 | ```
67 |
68 | If get `Uncaught ReferenceError: I18n is not defined` just add this line: `import I18n from './i18n'` in your ../public/javascripts/translations.js file
69 |
70 |
71 |
72 | Pull requests are welcome
73 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../stylesheets .css
3 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6 | * vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/admin/admins_controller.rb:
--------------------------------------------------------------------------------
1 | class Admin::AdminsController < ApplicationController
2 |
3 | layout 'admin/application'
4 | helper_method :admin?
5 |
6 | def index
7 | @users = User.all
8 |
9 | if admin?
10 | render 'admin/index'
11 | else
12 | redirect_to '/'
13 | end
14 |
15 | end
16 |
17 |
18 | private
19 |
20 | def admin?
21 | current_user && current_user.role == 1
22 | end
23 |
24 | end
--------------------------------------------------------------------------------
/app/controllers/api/vue_controller.rb:
--------------------------------------------------------------------------------
1 | module Api
2 | class VueController < ApplicationController
3 |
4 | def pass_data_to_vue
5 |
6 | @pass_data_to_vue = 'Data via Api Controller!'
7 | render json: { pass_data_to_vue: @pass_data_to_vue }
8 |
9 | end
10 |
11 | end
12 | end
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | before_action :set_locale
3 | helper_method :current_user, :set_user, :authenticated?, :is_this_user?
4 | def set_locale
5 | I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
6 | session[:locale] = I18n.locale
7 | end
8 |
9 | def default_url_options(options = {})
10 | { locale: I18n.locale }
11 | end
12 |
13 | def current_user
14 | if session[:user_id]
15 | @current_user ||= User.find(session[:user_id])
16 | else
17 | @current_user = nil
18 | end
19 | end
20 |
21 | def admin?
22 | current_user.role == 1
23 | end
24 |
25 | def set_user
26 | @user = User.find(params[:id])
27 | end
28 |
29 | def authenticated?
30 | redirect_to root_url unless current_user || @user
31 | end
32 |
33 | def is_this_user?
34 | redirect_to root_url if current_user.id != @user.id
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/landing_controller.rb:
--------------------------------------------------------------------------------
1 | class LandingController < ApplicationController
2 |
3 | def index
4 |
5 | @prop_to_vue = 'Variable from Rails View'
6 | render 'landing/index'
7 |
8 | end
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < ApplicationController
2 |
3 | def create
4 | user = User.find_by_email(params[:email])
5 | if user&.authenticate(params[:password])
6 | session[:user_id] = user.id
7 | user.role == 1 ? redirect_to(admin_root_path, notice: 'Is Admin') : redirect_to(user , notice: 'Not Admin')
8 | else
9 | flash.now[:alert] = I18n.t 'email_or_password_wrong'
10 | render 'users/login_register'
11 | end
12 | end
13 | def destroy
14 | session[:user_id] = nil
15 | redirect_to root_url, notice: 'Logged out!'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | class UsersController < ApplicationController
2 | before_action :set_user, only: %i[show update destroy]
3 | before_action :authenticated?, except: %i[enter create]
4 | before_action :is_this_user?, except: %i[enter create]
5 | # GET /users
6 | # GET /users.json
7 | def index
8 | @users = User.all
9 | end
10 |
11 | def enter
12 |
13 |
14 | @user = User.new
15 | @user.save
16 |
17 | if current_user
18 | redirect_to(current_user)
19 | else
20 | render('users/login_register')
21 |
22 |
23 | end
24 | end
25 |
26 | # GET /users/1
27 | # GET /users/1.json
28 | def show
29 | end
30 |
31 | # POST /users
32 | # POST /users.json
33 | def create
34 | @user = User.new(user_params)
35 | @user.save
36 | session[:user_id] = @user.id
37 | redirect_to @user, notice: I18n.t('user_registered')
38 | end
39 |
40 | # PATCH/PUT /users/1
41 | # PATCH/PUT /users/1.json
42 | def update
43 | @user.update_attributes(user_params)
44 | end
45 |
46 | # DELETE /users/1
47 | # DELETE /users/1.json
48 | def destroy
49 | @user.destroy
50 | respond_to do |format|
51 | format.html { redirect_to admin_root_path, notice: 'User was successfully destroyed.' }
52 | end
53 | end
54 |
55 | private
56 |
57 | # Never trust parameters from the scary internet, only allow the white list through.
58 | def user_params
59 | params.require(:user).permit(:email, :password, :password_confirmation, :role)
60 | end
61 |
62 |
63 | end
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/landing_helper.rb:
--------------------------------------------------------------------------------
1 | module LandingHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 | end
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 | end
--------------------------------------------------------------------------------
/app/javascript/additional/nav_responsive.js:
--------------------------------------------------------------------------------
1 | //Javascript to toggle the menu
2 |
3 | window.onload = function(){
4 | document.getElementById('nav-toggle').onclick = function(){
5 | document.getElementById("nav-content").classList.toggle("hidden");
6 | }
7 | }
--------------------------------------------------------------------------------
/app/javascript/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | This is a variable from Vue: {{message}}
7 | This is variable from Rails Api: {{pass_data_to_vue}}
8 | This is variable from Rails view via props: {{prop_to_vue}}
9 |
10 |
11 |
12 |
13 |
30 |
31 |
--------------------------------------------------------------------------------
/app/javascript/channels/consumer.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3 |
4 | import { createConsumer } from "@rails/actioncable"
5 |
6 | export default createConsumer()
7 |
--------------------------------------------------------------------------------
/app/javascript/channels/index.js:
--------------------------------------------------------------------------------
1 | // Load all the channels within this directory and all subdirectories.
2 | // Channel files must be named *_channel.js.
3 |
4 | const channels = require.context('.', true, /_channel\.js$/)
5 | channels.keys().forEach(channels)
6 |
--------------------------------------------------------------------------------
/app/javascript/components/VueComponent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Translated string in VueJS: {{ t('language') }}
4 | {{prop_from_rails_view}}
5 |
6 |
7 |
8 |
20 |
21 |
--------------------------------------------------------------------------------
/app/javascript/components/mixins/i18n_mixin.js:
--------------------------------------------------------------------------------
1 | import I18n from '../../../../public/javascripts/i18n'
2 | import '../../../../public/javascripts/translations'
3 |
4 | //Add "import I18n from './i18n'" to translations.js in public/javascripts folder
5 |
6 | I18n.defaultLocale = "en";
7 |
8 | document.addEventListener('turbolinks:load', () => {
9 | I18n.locale = document.getElementsByTagName("body")[0].getAttribute("lang");
10 | })
11 |
12 |
13 | export default {
14 | methods: {
15 | t: (args) => I18n.t(args),
16 |
17 | },
18 |
19 | }
--------------------------------------------------------------------------------
/app/javascript/css/application.css:
--------------------------------------------------------------------------------
1 | /**
2 | * This injects Tailwind's base styles, which is a combination of
3 | * Normalize.css and some additional base styles.
4 | *
5 | * You can see the styles here:
6 | * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
7 | *
8 | * If using `postcss-import`, use this import instead:
9 | *
10 | * @import "tailwindcss/preflight";
11 | */
12 | @tailwind base;
13 |
14 | /**
15 | * This injects any component classes registered by plugins.
16 | *
17 | * If using `postcss-import`, use this import instead:
18 | *
19 | * @import "tailwindcss/components";
20 | */
21 | @tailwind components;
22 |
23 | /**
24 | * Here you would add any of your custom component classes; stuff that you'd
25 | * want loaded *before* the utilities so that the utilities could still
26 | * override them.
27 | *
28 | * Example:
29 | *
30 | * .btn { ... }
31 | * .form-input { ... }
32 | *
33 | * Or if using a preprocessor or `postcss-import`:
34 | *
35 | * @import "components/buttons";
36 | * @import "components/forms";
37 | */
38 |
39 | /**
40 | * This injects all of Tailwind's utility classes, generated based on your
41 | * config file.
42 | *
43 | * If using `postcss-import`, use this import instead:
44 | *
45 | * @import "tailwindcss/utilities";
46 | */
47 | @tailwind utilities;
48 |
49 | /**
50 | * Here you would add any custom utilities you need that don't come out of the
51 | * box with Tailwind.
52 | *
53 | * Example :
54 | *
55 | * .bg-pattern-graph-paper { ... }
56 | * .skew-45 { ... }
57 | *
58 | * Or if using a preprocessor or `postcss-import`:
59 | *
60 | * @import "utilities/background-patterns";
61 | * @import "utilities/skew-transforms";
62 | */
--------------------------------------------------------------------------------
/app/javascript/css/carousel.css:
--------------------------------------------------------------------------------
1 | .carousel-open:checked + .carousel-item {
2 | position: static;
3 | opacity: 100;
4 | }
5 | .carousel-item {
6 | -webkit-transition: opacity 0.6s ease-out;
7 | transition: opacity 0.6s ease-out;
8 | }
9 | #carousel-1:checked ~ .control-1,
10 | #carousel-2:checked ~ .control-2,
11 | #carousel-3:checked ~ .control-3 {
12 | display: block;
13 | }
14 | .carousel-indicators {
15 | list-style: none;
16 | margin: 0;
17 | padding: 0;
18 | position: absolute;
19 | bottom: 2%;
20 | left: 0;
21 | right: 0;
22 | text-align: center;
23 | z-index: 10;
24 | }
25 | #carousel-1:checked ~ .control-1 ~ .carousel-indicators li:nth-child(1) .carousel-bullet,
26 | #carousel-2:checked ~ .control-2 ~ .carousel-indicators li:nth-child(2) .carousel-bullet,
27 | #carousel-3:checked ~ .control-3 ~ .carousel-indicators li:nth-child(3) .carousel-bullet {
28 | color: #2b6cb0; /*Set to match the Tailwind colour you want the active one to be */
29 | }
--------------------------------------------------------------------------------
/app/javascript/css/header.css:
--------------------------------------------------------------------------------
1 | /* ––––––––––––––––––––––––––––––––––––––––––––––––––
2 | Based on: https://codepen.io/nickelse/pen/YGPJQG
3 | Influenced by: https://sproutsocial.com/
4 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
5 |
6 |
7 | /* #Mega Menu Styles
8 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
9 | .mega-menu {
10 | display: none;
11 | left: 0;
12 | position: absolute;
13 | text-align: left;
14 | width: 100%;
15 | }
16 |
17 |
18 |
19 | /* #hoverable Class Styles
20 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
21 | .hoverable {
22 | position: static;
23 | }
24 |
25 | .hoverable > a:after {
26 | content: "\25BC";
27 | font-size: 10px;
28 | padding-left: 6px;
29 | position: relative;
30 | top: -1px;
31 | }
32 |
33 | .hoverable:hover .mega-menu {
34 | display: block;
35 | }
36 |
37 |
38 | /* #toggle Class Styles
39 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
40 |
41 | .toggleable > label:after {
42 | content: "\25BC";
43 | font-size: 10px;
44 | padding-left: 6px;
45 | position: relative;
46 | top: -1px;
47 | }
48 |
49 | .toggle-input {
50 | display: none;
51 | }
52 | .toggle-input:not(checked) ~ .mega-menu {
53 | display: none;
54 | }
55 |
56 | .toggle-input:checked ~ .mega-menu {
57 | display: block;
58 | }
59 |
60 | .toggle-input:checked + label {
61 | color: white;
62 | background: #2c5282; /*@apply bg-blue-800 */
63 | }
64 |
65 | .toggle-input:checked ~ label:after {
66 | content: "\25B2";
67 | font-size: 10px;
68 | padding-left: 6px;
69 | position: relative;
70 | top: -1px;
71 | }
--------------------------------------------------------------------------------
/app/javascript/css/tailwind.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {
3 | extend: {
4 | colors: {
5 | 'custom': '#00b981',
6 | },
7 | }
8 | },
9 | variants: {},
10 | plugins: []
11 | }
12 |
--------------------------------------------------------------------------------
/app/javascript/images/rails_vuejs_tailwindcss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/app/javascript/images/rails_vuejs_tailwindcss.png
--------------------------------------------------------------------------------
/app/javascript/packs/application.js:
--------------------------------------------------------------------------------
1 | // This file is automatically compiled by Webpack, along with any other files
2 | // present in this directory. You're encouraged to place your actual application logic in
3 | // a relevant structure within app/javascript and only use these pack files to reference
4 | // that code so it'll be compiled.
5 |
6 | require("@rails/ujs").start();
7 | require("turbolinks").start();
8 | require("@rails/activestorage").start();
9 | require("channels");
10 |
11 | import '../css/application.css';
12 | import '../css/header.css';
13 | import '../css/carousel.css';
14 | import '@fortawesome/fontawesome';
15 | import '@fortawesome/fontawesome-free-solid';
16 |
17 | document.addEventListener("turbolinks:load", function() {
18 | FontAwesome.dom.i2svg();
19 | });
20 |
21 | // Uncomment to copy all static images under ../images to the output folder and reference
22 | // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
23 | // or the `imagePath` JavaScript helper below.
24 | //
25 | const images = require.context('../images', true);
26 | //const imagePath = (name) => images(name, true)
27 |
28 | //VueJS
29 | /*import Vue from 'vue';*/
30 | import Vue from 'vue/dist/vue.esm'
31 | import TurbolinksAdapter from 'vue-turbolinks';
32 | Vue.use(TurbolinksAdapter)
33 | import App from '../app';
34 | import axios from 'axios';
35 | Vue.prototype.$http = axios;
36 |
37 | import SecondComponent from "../components/VueComponent";
38 |
39 | document.addEventListener('turbolinks:load', () => {
40 | new Vue({
41 | el: '#app',
42 | data: () => {
43 | return {
44 | message: 'Message from application.js file'
45 | }
46 | },
47 | components: { App, SecondComponent }
48 | })
49 | });
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | # Automatically retry jobs that encountered a deadlock
3 | # retry_on ActiveRecord::Deadlocked
4 |
5 | # Most jobs are safe to ignore if the underlying records are no longer available
6 | # discard_on ActiveJob::DeserializationError
7 | end
8 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 | has_secure_password
3 |
4 | validates :email, presence: true, uniqueness: true
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/admin/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= render 'layouts/admin/sidebar' %>
6 |
7 |
8 |
9 | <% unless notice.nil? %>
10 |
18 | <% end %>
19 |
20 |
Analytics
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
Total Revenue
33 | $3249
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
Total Users
48 | 249
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
61 |
62 |
New Users
63 | 2
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
Server Uptime
78 | 152 days
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
91 |
92 |
To Do List
93 | 7 tasks
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
106 |
107 |
Issues
108 | 3
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
Users
124 |
125 |
126 | <% @current_user.role %>
127 | <% @users.each do |user| %>
128 |
129 | <%= user.email %>
130 | <%= link_to 'Show', user %>
131 | <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>
132 |
133 | <% end %>
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
Table
148 |
149 |
150 |
151 |
152 |
153 | Name
154 | Side
155 | Role
156 |
157 |
158 |
159 |
160 |
161 | Obi Wan Kenobi
162 | Light
163 | Jedi
164 |
165 |
166 | Greedo
167 | South
168 | Scumbag
169 |
170 |
171 | Darth Vader
172 | Dark
173 | Sith
174 |
175 |
176 |
177 |
178 |
See More issues...
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
Template
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
--------------------------------------------------------------------------------
/app/views/landing/index.html.erb:
--------------------------------------------------------------------------------
1 |
4 |
5 | <%= render 'layouts/second_component' %>
--------------------------------------------------------------------------------
/app/views/layouts/_carousel-slider.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
‹
9 |
›
10 |
11 |
12 |
13 |
16 |
‹
17 |
›
18 |
19 |
20 |
21 |
24 |
‹
25 |
›
26 |
27 |
28 |
29 |
30 | •
31 |
32 |
33 | •
34 |
35 |
36 | •
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Footer!
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/views/layouts/_header.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to root_path do %>
5 | <%= image_pack_tag 'rails_vuejs_tailwindcss.png', width: "220", alt: "Logo" %>
6 | <% end %>
7 |
8 |
9 |
10 |
11 | Normal
12 |
13 |
14 |
15 | <%= t(:text) %>
16 |
17 |
18 |
19 |
Main Hero Message for the menu section
20 |
Sub-hero message, not too long and not too short. Make it just right!
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Heading 1
28 |
29 | Quarterly sales are at an all-time low create spaces to explore the accountable talk and blind vampires.
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
Heading 2
43 |
44 | Prioritize these line items game-plan draw a line in the sand come up with something buzzworthy UX upstream selling.
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
Heading 3
58 |
59 | This proposal is a win-win situation which will cause a stellar paradigm shift, let's touch base off-line before we fire the new ux experience.
60 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
Heading 4
73 |
74 | This is a no-brainer to wash your face, or we need to future-proof this high performance keywords granularity.
75 |
81 |
82 |
83 |
84 |
85 |
86 | <% if current_user %>
87 |
88 |
89 | <%= current_user.email %>
90 |
91 |
92 |
93 | <% if current_user.role == 1 %>
94 | <%= link_to t(:control_panel), admin_root_path, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
95 | <% else %>
96 | <%= link_to t(:cabinet), user_path(id: current_user.id), class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
97 | <% end %>
98 | <%= link_to t(:exit), logout_path, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
99 |
100 |
101 | <% else %>
102 | <%= link_to 'enter', class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" do %>
103 |
104 | <%= t(:enter) %>
105 | <% end %>
106 | <% end %>
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | <%= t(:language) %>
115 |
116 |
117 |
118 | <%= link_to "Русский", {locale: :ru}, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
119 | <%= link_to "English", {locale: :en}, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/app/views/layouts/_second_component.html.erb:
--------------------------------------------------------------------------------
1 | <% @prop_from_rails_view = 'PropFromRailsView' %>
2 |
3 |
--------------------------------------------------------------------------------
/app/views/layouts/admin/_nav.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= link_to root_path do %>
7 | <%= image_pack_tag 'rails_vuejs_tailwindcss.png', width: "220", alt: "Logo" %>
8 | <% end %>
9 |
10 |
11 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | <%= t(:language) %>
30 |
31 |
32 |
33 | <%= link_to "Русский", {locale: :ru}, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
34 | <%= link_to "Українська", {locale: :ua}, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
35 |
36 |
37 |
38 |
39 |
40 | <% if current_user %>
41 |
42 |
43 | <%= current_user.email %>
44 |
45 |
46 |
47 | <%= link_to t(:exit), logout_path, class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" %>
48 |
49 |
50 | <% else %>
51 | <%= link_to 'enter', class: "relative block py-6 px-2 lg:p-6 text-sm text-lg font-bold" do %>
52 |
53 | <%= t(:enter) %>
54 | <% end %>
55 | <% end %>
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/views/layouts/admin/_sidebar.html.erb:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/app/views/layouts/admin/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Admin Starter Template : Tailwind Toolbox
9 | <%= csrf_meta_tags %>
10 | <%= csp_meta_tag %>
11 | <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
12 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
13 |
14 |
15 |
16 |
17 |
18 | <%= render 'layouts/admin/nav' %>
19 |
20 |
21 | <%= yield %>
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Rails 6 + VueJS + TailwindCSS with turbolinks Starter Kit
5 | <%= csrf_meta_tags %>
6 | <%= csp_meta_tag %>
7 | <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
8 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
9 |
10 |
11 |
12 | <%= render 'layouts/header' %>
13 |
14 |
15 |
16 |
17 | <%= yield %>
18 |
19 |
20 |
21 |
22 | <%= render 'layouts/footer' %>
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/users/_cabinet_nav.html.erb:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/app/views/users/_login_form.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= form_tag sessions_path do %>
4 |
<%= t(:enter_cabinet) %>
5 |
6 | <% unless alert.nil? %>
7 |
8 | <%= t(:attention) %>!
9 | <%= alert %>.
10 |
11 |
12 |
13 | <% end %>
14 |
15 |
16 |
17 | <%= label_tag 'E-mail', nil, :class => "font-bold text-grey-darker block mb-2" %>
18 | <%= text_field_tag :email, nil, :class => "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
19 |
20 |
21 |
22 | <%= label_tag t(:password), nil, :class => "font-bold text-grey-darker block mb-2" %>
23 | <%= password_field_tag :password, nil, autocomplete: "current-password", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
24 |
25 |
26 |
27 |
28 | <%= submit_tag t(:enter), class: "bg-custom hover:bg-black text-white hover:text-custom font-bold py-2 px-4 rounded" %>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | <% end %>
41 |
--------------------------------------------------------------------------------
/app/views/users/_registration_form.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= form_with(model: @user, local: true) do |f| %>
4 |
<%= t(:register) %>
5 |
6 |
7 |
8 | <%= f.label :email, class: "font-bold text-grey-darker block mb-2" %>
9 | <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
10 |
11 |
12 |
13 | <%= f.label t(:password), class: "font-bold text-grey-darker block mb-2" %>
14 | <%= f.password_field :password, autocomplete: "new-password", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
15 |
16 |
17 |
18 |
19 | <%= f.label t(:confirm_password), class: "font-bold text-grey-darker block mb-2" %>
20 | <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
21 |
22 |
23 |
24 | <%= f.submit t(:register), class: "bg-custom hover:bg-black text-white hover:text-custom font-bold py-2 px-4 rounded" %>
25 |
26 |
27 |
28 | <% end %>
29 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 | <%= notice %>
2 |
3 | Users
4 |
5 |
6 |
7 |
8 | Email
9 |
10 |
11 |
12 |
13 |
14 | <% @users.each do |user| %>
15 |
16 | <%= user.email %>
17 | <%= link_to 'Show', user %>
18 | <%= link_to 'Edit', edit_user_path(user) %>
19 | <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>
20 |
21 | <% end %>
22 |
23 |
24 |
25 |
26 |
27 | <%= link_to 'New User', new_user_path %>
28 |
--------------------------------------------------------------------------------
/app/views/users/login_register.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render 'users/login_form' %>
4 | <%= render 'users/registration_form', user: @user_new %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render 'users/cabinet_nav' %>
4 |
5 |
6 | <%= form_with(model: @user, local: true) do |f| %>
7 |
8 | <% unless notice.nil? %>
9 |
17 | <% end %>
18 |
19 | <%= f.label :email, class: "font-bold text-grey-darker block mb-2" %>
20 | <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
21 |
22 |
23 |
24 | <%= f.label t(:password), class: "font-bold text-grey-darker block mb-2" %>
25 | <%= f.password_field :password, autocomplete: "new-password", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
26 |
27 |
28 |
29 |
30 | <%= f.label t(:confirm_password), class: "font-bold text-grey-darker block mb-2" %>
31 | <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "block appearance-none w-full bg-white border border-grey-light hover:border-grey px-2 py-2 rounded shadow" %>
32 |
33 |
34 |
35 | <%= f.submit t(:save), class: "bg-custom hover:bg-black text-white hover:text-custom font-bold py-2 px-4 rounded" %>
36 |
37 |
38 |
39 | <% end %>
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | var validEnv = ['development', 'test', 'production']
3 | var currentEnv = api.env()
4 | var isDevelopmentEnv = api.env('development')
5 | var isProductionEnv = api.env('production')
6 | var isTestEnv = api.env('test')
7 |
8 | if (!validEnv.includes(currentEnv)) {
9 | throw new Error(
10 | 'Please specify a valid `NODE_ENV` or ' +
11 | '`BABEL_ENV` environment variables. Valid values are "development", ' +
12 | '"test", and "production". Instead, received: ' +
13 | JSON.stringify(currentEnv) +
14 | '.'
15 | )
16 | }
17 |
18 | return {
19 | presets: [
20 | isTestEnv && [
21 | require('@babel/preset-env').default,
22 | {
23 | targets: {
24 | node: 'current'
25 | }
26 | }
27 | ],
28 | (isProductionEnv || isDevelopmentEnv) && [
29 | require('@babel/preset-env').default,
30 | {
31 | forceAllTransforms: true,
32 | useBuiltIns: 'entry',
33 | corejs: 3,
34 | modules: false,
35 | exclude: ['transform-typeof-symbol']
36 | }
37 | ]
38 | ].filter(Boolean),
39 | plugins: [
40 | require('babel-plugin-macros'),
41 | require('@babel/plugin-syntax-dynamic-import').default,
42 | isTestEnv && require('babel-plugin-dynamic-import-node'),
43 | require('@babel/plugin-transform-destructuring').default,
44 | [
45 | require('@babel/plugin-proposal-class-properties').default,
46 | {
47 | loose: true
48 | }
49 | ],
50 | [
51 | require('@babel/plugin-proposal-object-rest-spread').default,
52 | {
53 | useBuiltIns: true
54 | }
55 | ],
56 | [
57 | require('@babel/plugin-transform-runtime').default,
58 | {
59 | helpers: false,
60 | regenerator: true,
61 | corejs: false
62 | }
63 | ],
64 | [
65 | require('@babel/plugin-transform-regenerator').default,
66 | {
67 | async: false
68 | }
69 | ]
70 | ].filter(Boolean)
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'bundle' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | require "rubygems"
12 |
13 | m = Module.new do
14 | module_function
15 |
16 | def invoked_as_script?
17 | File.expand_path($0) == File.expand_path(__FILE__)
18 | end
19 |
20 | def env_var_version
21 | ENV["BUNDLER_VERSION"]
22 | end
23 |
24 | def cli_arg_version
25 | return unless invoked_as_script? # don't want to hijack other binstubs
26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27 | bundler_version = nil
28 | update_index = nil
29 | ARGV.each_with_index do |a, i|
30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31 | bundler_version = a
32 | end
33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34 | bundler_version = $1 || ">= 0.a"
35 | update_index = i
36 | end
37 | bundler_version
38 | end
39 |
40 | def gemfile
41 | gemfile = ENV["BUNDLE_GEMFILE"]
42 | return gemfile if gemfile && !gemfile.empty?
43 |
44 | File.expand_path("../../Gemfile", __FILE__)
45 | end
46 |
47 | def lockfile
48 | lockfile =
49 | case File.basename(gemfile)
50 | when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51 | else "#{gemfile}.lock"
52 | end
53 | File.expand_path(lockfile)
54 | end
55 |
56 | def lockfile_version
57 | return unless File.file?(lockfile)
58 | lockfile_contents = File.read(lockfile)
59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60 | Regexp.last_match(1)
61 | end
62 |
63 | def bundler_version
64 | @bundler_version ||= begin
65 | env_var_version || cli_arg_version ||
66 | lockfile_version || "#{Gem::Requirement.default}.a"
67 | end
68 | end
69 |
70 | def load_bundler!
71 | ENV["BUNDLE_GEMFILE"] ||= gemfile
72 |
73 | # must dup string for RG < 1.8 compatibility
74 | activate_bundler(bundler_version.dup)
75 | end
76 |
77 | def activate_bundler(bundler_version)
78 | if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79 | bundler_version = "< 2"
80 | end
81 | gem_error = activation_error_handling do
82 | gem "bundler", bundler_version
83 | end
84 | return if gem_error.nil?
85 | require_error = activation_error_handling do
86 | require "bundler/version"
87 | end
88 | return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89 | warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90 | exit 42
91 | end
92 |
93 | def activation_error_handling
94 | yield
95 | nil
96 | rescue StandardError, LoadError => e
97 | e
98 | end
99 | end
100 |
101 | m.load_bundler!
102 |
103 | if m.invoked_as_script?
104 | load Gem.bin_path("bundler", "bundle")
105 | end
106 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 |
4 | # path to your application root.
5 | APP_ROOT = File.expand_path('..', __dir__)
6 |
7 | def system!(*args)
8 | system(*args) || abort("\n== Command #{args} failed ==")
9 | end
10 |
11 | FileUtils.chdir APP_ROOT do
12 | # This script is a way to setup or update your development environment automatically.
13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies
21 | # system('bin/yarn')
22 |
23 | # puts "\n== Copying sample files =="
24 | # unless File.exist?('config/database.yml')
25 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
26 | # end
27 |
28 | puts "\n== Preparing database =="
29 | system! 'bin/rails db:prepare'
30 |
31 | puts "\n== Removing old logs and tempfiles =="
32 | system! 'bin/rails log:clear tmp:clear'
33 |
34 | puts "\n== Restarting application server =="
35 | system! 'bin/rails restart'
36 | end
37 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads Spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/bin/webpack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/webpack_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::WebpackRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/bin/webpack-dev-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/dev_server_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::DevServerRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 | require 'rails/all'
3 |
4 | # Require the gems listed in Gemfile, including any gems
5 | # you've limited to :test, :development, or :production.
6 | Bundler.require(*Rails.groups)
7 |
8 | module RailsVueJS
9 | class Application < Rails::Application
10 | # Initialize configuration defaults for originally generated Rails version.
11 | config.load_defaults 6.0
12 | # Settings in config/environments/* take precedence over those specified here.
13 | # Application configuration can go into files in config/initializers
14 | # -- all .rb files in that directory are automatically loaded after loading
15 | # the framework and any gems in your application.
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: test
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: railsvuejs_production
11 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | DqT0oUrBUii2ZJrNhVzo6pUasKVPHEhcBnQVznnDg+MKCLharirpJ8b26DtqNXowwyG8faLoW9v0ymBjEg5xb26wu8cNUj+yKTmcAOXg5gGSKbuXO4WndS4R0D4vPH2BML0w7UMmZ4sDDgVyNo2J+JhVsICFOesUqTUav5Qjc9zB9cxS34qkOZrESndCVWijI7SHy8ikcAd43Rdf6VgERSuVaR914yXVtwrrL7CIO5OxiSsntHeAyHsjCOqh1MlqGl8yG86+BQNcyUERr5AaktPZ6mRTauWnTXA8V+lEeuupCtxvZh7zFNohOD/Ee3dm6rt9jYljNrTowIxsp57Kl4dbsiLPY5k/oscpHrE6F0/S4Uh72oEhP7OE6URgVxOhvdGOVZxduV+HsTtriTtf530ienaxm7pWaKDl--giuBRW4IKxjqZZwH--MjiCV01hWyNIU8eCzazxAw==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 9.3 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On macOS with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On macOS with MacPorts:
8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
9 | # On Windows:
10 | # gem install pg
11 | # Choose the win32 build.
12 | # Install PostgreSQL and put its /bin directory on your path.
13 | #
14 | # Configure Using Gemfile
15 | # gem 'pg'
16 | #
17 | default: &default
18 | adapter: postgresql
19 | encoding: unicode
20 | # For details on connection pooling, see Rails configuration guide
21 | # https://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
23 |
24 | development:
25 | <<: *default
26 | database: railsvuejs_development
27 |
28 | # The specified database role being used to connect to postgres.
29 | # To create additional roles in postgres see `$ createuser --help`.
30 | # When left blank, postgres will use the default role. This is
31 | # the same name as the operating system user that initialized the database.
32 | username: postgres
33 |
34 | # The password associated with the postgres role (username).
35 | password: 12345
36 |
37 | # Connect on a TCP socket. Omitted by default since the client uses a
38 | # domain socket that doesn't need configuration. Windows does not have
39 | # domain sockets, so uncomment these lines.
40 | #host: localhost
41 |
42 | # The TCP port the server listens on. Defaults to 5432.
43 | # If your server runs on a different port number, change accordingly.
44 | #port: 5432
45 |
46 | # Schema search path. The server defaults to $user,public
47 | #schema_search_path: myapp,sharedapp,public
48 |
49 | # Minimum log levels, in increasing order:
50 | # debug5, debug4, debug3, debug2, debug1,
51 | # log, notice, warning, error, fatal, and panic
52 | # Defaults to warning.
53 | #min_messages: notice
54 |
55 | # Warning: The database defined as "test" will be erased and
56 | # re-generated from your development database when you run "rake".
57 | # Do not set this db to the same as development or production.
58 | test:
59 | <<: *default
60 | database: railvuejs_test
61 |
62 | # As with config/credentials.yml, you never want to store sensitive information,
63 | # like your database password, in your source code. If your source code is
64 | # ever seen by anyone, they now have access to your database.
65 | #
66 | # Instead, provide the password as a unix environment variable when you boot
67 | # the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
68 | # for a full rundown on how to provide these environment variables in a
69 | # production deployment.
70 | #
71 | # On Heroku and other platform providers, you may have a full connection URL
72 | # available as an environment variable. For example:
73 | #
74 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
75 | #
76 | # You can use this database configuration with:
77 | #
78 | # production:
79 | # url: <%= ENV['DATABASE_URL'] %>
80 | #
81 | production:
82 | <<: *default
83 | database: railsvuejs_production
84 | username: postgres
85 | password: <%= ENV['RAILSVUEJS_DATABASE_PASSWORD'] %>
86 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 | EncryptedFormFields.secret_key_base = Rails.application.secret_key_base
7 | EncryptedFormFields.secret_token = SecureRandom.hex(64)
8 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | # Run rails dev:cache to toggle caching.
17 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
18 | config.action_controller.perform_caching = true
19 | config.action_controller.enable_fragment_cache_logging = true
20 |
21 | config.cache_store = :memory_store
22 | config.public_file_server.headers = {
23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
24 | }
25 | else
26 | config.action_controller.perform_caching = false
27 |
28 | config.cache_store = :null_store
29 | end
30 |
31 | # Store uploaded files on the local file system (see config/storage.yml for options).
32 | config.active_storage.service = :local
33 |
34 | # Don't care if the mailer can't send.
35 | config.action_mailer.raise_delivery_errors = false
36 |
37 | config.action_mailer.perform_caching = false
38 |
39 | # Print deprecation notices to the Rails logger.
40 | config.active_support.deprecation = :log
41 |
42 | # Raise an error on page load if there are pending migrations.
43 | config.active_record.migration_error = :page_load
44 |
45 | # Highlight code that triggered database queries in logs.
46 | config.active_record.verbose_query_logs = true
47 |
48 | # Debug mode disables concatenation and preprocessing of assets.
49 | # This option may cause significant delays in view rendering with a large
50 | # number of complex assets.
51 | config.assets.debug = true
52 |
53 | # Suppress logger output for asset requests.
54 | config.assets.quiet = true
55 |
56 | # Raises error for missing translations.
57 | # config.action_view.raise_on_missing_translations = true
58 |
59 | # Use an evented file watcher to asynchronously detect changes in source code,
60 | # routes, locales, etc. This feature depends on the listen gem.
61 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
62 |
63 | #Local domain availability
64 | config.hosts.clear
65 | end
66 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
19 | # config.require_master_key = true
20 |
21 | # Disable serving static files from the `/public` folder by default since
22 | # Apache or NGINX already handles this.
23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
24 |
25 | # Compress CSS using a preprocessor.
26 | # config.assets.css_compressor = :sass
27 |
28 | # Do not fallback to assets pipeline if a precompiled asset is missed.
29 | config.assets.compile = false
30 |
31 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
32 | # config.action_controller.asset_host = 'http://assets.example.com'
33 |
34 | # Specifies the header that your server uses for sending files.
35 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
36 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
37 |
38 | # Store uploaded files on the local file system (see config/storage.yml for options).
39 | config.active_storage.service = :local
40 |
41 | # Mount Action Cable outside main process or domain.
42 | # config.action_cable.mount_path = nil
43 | # config.action_cable.url = 'wss://example.com/cable'
44 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
45 |
46 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
47 | # config.force_ssl = true
48 |
49 | # Use the lowest log level to ensure availability of diagnostic information
50 | # when problems arise.
51 | config.log_level = :debug
52 |
53 | # Prepend all log lines with the following tags.
54 | config.log_tags = [ :request_id ]
55 |
56 | # Use a different cache store in production.
57 | # config.cache_store = :mem_cache_store
58 |
59 | # Use a real queuing backend for Active Job (and separate queues per environment).
60 | # config.active_job.queue_adapter = :resque
61 | # config.active_job.queue_name_prefix = "railsvuejs_production"
62 |
63 | config.action_mailer.perform_caching = false
64 |
65 | # Ignore bad email addresses and do not raise email delivery errors.
66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
67 | # config.action_mailer.raise_delivery_errors = false
68 |
69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
70 | # the I18n.default_locale when a translation cannot be found).
71 | config.i18n.fallbacks = true
72 |
73 | # Send deprecation notices to registered listeners.
74 | config.active_support.deprecation = :notify
75 |
76 | # Use default logging formatter so that PID and timestamp are not suppressed.
77 | config.log_formatter = ::Logger::Formatter.new
78 |
79 | # Use a different logger for distributed setups.
80 | # require 'syslog/logger'
81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
82 |
83 | if ENV["RAILS_LOG_TO_STDOUT"].present?
84 | logger = ActiveSupport::Logger.new(STDOUT)
85 | logger.formatter = config.log_formatter
86 | config.logger = ActiveSupport::TaggedLogging.new(logger)
87 | end
88 |
89 | # Do not dump schema after migrations.
90 | config.active_record.dump_schema_after_migration = false
91 |
92 | # Inserts middleware to perform automatic connection switching.
93 | # The `database_selector` hash is used to pass options to the DatabaseSelector
94 | # middleware. The `delay` is used to determine how long to wait after a write
95 | # to send a subsequent read to the primary.
96 | #
97 | # The `database_resolver` class is used by the middleware to determine which
98 | # database is appropriate to use based on the time delay.
99 | #
100 | # The `database_resolver_context` class is used by the middleware to set
101 | # timestamps for the last write to the primary. The resolver uses the context
102 | # class timestamps to determine how long to wait before reading from the
103 | # replica.
104 | #
105 | # By default Rails will store a last write timestamp in the session. The
106 | # DatabaseSelector middleware is designed as such you can define your own
107 | # strategy for connection switching and pass that into the middleware through
108 | # these configuration options.
109 | # config.active_record.database_selector = { delay: 2.seconds }
110 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
111 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
112 | end
113 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # The test environment is used exclusively to run your application's
2 | # test suite. You never need to work with it otherwise. Remember that
3 | # your test database is "scratch space" for the test suite and is wiped
4 | # and recreated between test runs. Don't rely on the data there!
5 |
6 | Rails.application.configure do
7 | # Settings specified here will take precedence over those in config/application.rb.
8 |
9 | config.cache_classes = false
10 |
11 | # Do not eager load code on boot. This avoids loading your whole application
12 | # just for the purpose of running a single test. If you are using a tool that
13 | # preloads Rails for running tests, you may have to set it to true.
14 | config.eager_load = false
15 |
16 | # Configure public file server for tests with Cache-Control for performance.
17 | config.public_file_server.enabled = true
18 | config.public_file_server.headers = {
19 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
20 | }
21 |
22 | # Show full error reports and disable caching.
23 | config.consider_all_requests_local = true
24 | config.action_controller.perform_caching = false
25 | config.cache_store = :null_store
26 |
27 | # Raise exceptions instead of rendering exception templates.
28 | config.action_dispatch.show_exceptions = false
29 |
30 | # Disable request forgery protection in test environment.
31 | config.action_controller.allow_forgery_protection = false
32 |
33 | # Store uploaded files on the local file system in a temporary directory.
34 | config.active_storage.service = :test
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Tell Action Mailer not to deliver emails to the real world.
39 | # The :test delivery method accumulates sent emails in the
40 | # ActionMailer::Base.deliveries array.
41 | config.action_mailer.delivery_method = :test
42 |
43 | # Print deprecation notices to the stderr.
44 | config.active_support.deprecation = :stderr
45 |
46 | # Raises error for missing translations.
47 | # config.action_view.raise_on_missing_translations = true
48 | end
49 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 | # Precompile additional assets.
11 | # application.js, application.css, and all non-JS/CSS in the app/assets
12 | # folder are already added.
13 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
14 |
15 | Rails.application.config.middleware.use I18n::JS::Middleware
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 | # # If you are using webpack-dev-server then specify webpack-dev-server host
15 | # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
16 |
17 | # # Specify URI for violation reports
18 | # # policy.report_uri "/csp-violation-report-endpoint"
19 | # end
20 |
21 | # If you are using UJS then enable automatic nonce generation
22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
23 |
24 | # Set the nonce only to specific directives
25 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
26 |
27 | # Report CSP violations to a specified URI
28 | # For further information see the following documentation:
29 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
30 | # Rails.application.config.content_security_policy_report_only = true
31 |
32 | Rails.application.config.content_security_policy do |policy|
33 | if Rails.env.development?
34 | policy.script_src :self, :https, :unsafe_inline, :unsafe_eval
35 | policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035'
36 | else
37 | policy.script_src :self, :https
38 | end
39 | end
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/locale.rb:
--------------------------------------------------------------------------------
1 | # где библиотека I18n должна искать наши переводы
2 | I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')]
3 |
4 | # Разрешенные локали, доступные приложению
5 | I18n.available_locales = %i[en ru]
6 |
7 | # устанавливаем локаль по умолчанию на что-либо другое, чем :en
8 | I18n.default_locale = :en
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | text: "Text"
3 | language: "Language"
4 |
5 | enter: 'Enter'
6 | enter_cabinet: 'Enter in account'
7 | register: 'Registration'
8 | forgot_password: 'Forgot password?'
9 | remember_me: 'Remember'
10 | password: 'Password'
11 | confirm_password: 'Confirm password'
12 | cabinet: 'Account'
13 | exit: 'Exit'
14 | attention: 'Attention'
15 | email_or_password_wrong: 'The specified e-mail is not registered, or the password is incorrect'
16 | save: 'Save'
17 | control_panel: 'Dashboard'
18 | user_registered: 'User successfully registered'
19 |
--------------------------------------------------------------------------------
/config/locales/ru.yml:
--------------------------------------------------------------------------------
1 | ru:
2 | text: "Текст"
3 | language: "Язык"
4 |
5 | enter: 'Вход'
6 | enter_cabinet: 'Вход в кабинет'
7 | register: 'Регистрация'
8 | forgot_password: 'Забыли пароль?'
9 | remember_me: 'Запомнить'
10 | password: 'Пароль'
11 | confirm_password: 'Подтвердите пароль'
12 | cabinet: 'Кабинет'
13 | exit: 'Выход'
14 | attention: 'Внимание'
15 | email_or_password_wrong: 'Указанный e-mail не зарегистрирован, либо указан неверный пароль'
16 | save: 'Сохранить'
17 | control_panel: 'Панель управления'
18 | user_registered: 'Пользователь успешно зарегистрирован'
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
9 | threads min_threads_count, max_threads_count
10 |
11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
12 | #
13 | port ENV.fetch("PORT") { 3000 }
14 |
15 | # Specifies the `environment` that Puma will run in.
16 | #
17 | environment ENV.fetch("RAILS_ENV") { "development" }
18 |
19 | # Specifies the `pidfile` that Puma will use.
20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
21 |
22 | # Specifies the number of `workers` to boot in clustered mode.
23 | # Workers are forked web server processes. If using threads and workers together
24 | # the concurrency of the application would be max `threads` * `workers`.
25 | # Workers do not work on JRuby or Windows (both of which do not support
26 | # processes).
27 | #
28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
29 |
30 | # Use the `preload_app!` method when specifying a `workers` number.
31 | # This directive tells Puma to first boot the application and load code
32 | # before forking the application. This takes advantage of Copy On Write
33 | # process behavior so workers use less memory.
34 | #
35 | # preload_app!
36 |
37 | # Allow puma to be restarted by `rails restart` command.
38 | plugin :tmp_restart
39 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
3 |
4 | namespace :api do
5 | get 'vue/data', to: 'vue#pass_data_to_vue'
6 |
7 | end
8 |
9 | scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
10 |
11 | namespace :admin do
12 |
13 | root 'admins#index'
14 |
15 | end
16 |
17 |
18 | root to: 'landing#index'
19 |
20 | # Users
21 | resources :users
22 | resources :sessions, only: [:create, :destroy]
23 | get 'enter', to: 'users#enter', as: 'enter'
24 | get 'logout', to: 'sessions#destroy', as: 'logout'
25 |
26 | get 'sessions/new'
27 | get 'sessions/create'
28 | get 'sessions/destroy'
29 |
30 | end
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | Spring.watch(
2 | ".ruby-version",
3 | ".rbenv-vars",
4 | "tmp/restart.txt",
5 | "tmp/caching-dev.txt"
6 | )
7 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/config/webpack/development.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpack/environment.js:
--------------------------------------------------------------------------------
1 | const { environment } = require('@rails/webpacker')
2 | const { VueLoaderPlugin } = require('vue-loader')
3 | const vue = require('./loaders/vue')
4 |
5 | environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
6 | environment.loaders.prepend('vue', vue)
7 | module.exports = environment
8 |
--------------------------------------------------------------------------------
/config/webpack/loaders/vue.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | test: /\.vue(\.erb)?$/,
3 | use: [{
4 | loader: 'vue-loader'
5 | }]
6 | }
7 |
--------------------------------------------------------------------------------
/config/webpack/production.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpack/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpacker.yml:
--------------------------------------------------------------------------------
1 | # Note: You must restart bin/webpack-dev-server for changes to take effect
2 |
3 | default: &default
4 | source_path: app/javascript
5 | source_entry_path: packs
6 | public_root_path: public
7 | public_output_path: packs
8 | cache_path: tmp/cache/webpacker
9 | check_yarn_integrity: false
10 | webpack_compile_output: false
11 |
12 | # Additional paths webpack should lookup modules
13 | # ['app/assets', 'engine/foo/app/assets']
14 | resolved_paths: ['app/javascript/additional']
15 |
16 | # Reload manifest.json on all requests so we reload latest compiled packs
17 | cache_manifest: false
18 |
19 | # Extract and emit a css file
20 | extract_css: false
21 |
22 | static_assets_extensions:
23 | - .jpg
24 | - .jpeg
25 | - .png
26 | - .gif
27 | - .tiff
28 | - .ico
29 | - .svg
30 | - .eot
31 | - .otf
32 | - .ttf
33 | - .woff
34 | - .woff2
35 |
36 | extensions:
37 | - .vue
38 | - .mjs
39 | - .js
40 | - .sass
41 | - .scss
42 | - .css
43 | - .module.sass
44 | - .module.scss
45 | - .module.css
46 | - .png
47 | - .svg
48 | - .gif
49 | - .jpeg
50 | - .jpg
51 |
52 | development:
53 | <<: *default
54 | compile: true
55 |
56 | # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
57 | check_yarn_integrity: true
58 |
59 | # Reference: https://webpack.js.org/configuration/dev-server/
60 | dev_server:
61 | https: false
62 | host: localhost
63 | port: 3035
64 | public: localhost:3035
65 | hmr: false
66 | # Inline should be set to true if using HMR
67 | inline: true
68 | overlay: true
69 | compress: true
70 | disable_host_check: true
71 | use_local_ip: false
72 | quiet: false
73 | headers:
74 | 'Access-Control-Allow-Origin': '*'
75 | watch_options:
76 | ignored: '**/node_modules/**'
77 |
78 |
79 | test:
80 | <<: *default
81 | compile: true
82 |
83 | # Compile test packs to a separate directory
84 | public_output_path: packs-test
85 |
86 | production:
87 | <<: *default
88 |
89 | # Production depends on precompilation of packs prior to booting for performance.
90 | compile: false
91 |
92 | # Extract and emit a css file
93 | extract_css: true
94 |
95 | # Cache manifest.json for performance
96 | cache_manifest: true
97 |
--------------------------------------------------------------------------------
/db/migrate/20190913103805_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :users do |t|
4 | t.string :email
5 | t.string :password_digest
6 | t.integer :role, default: 2, comment: '1. Admin 2. Customer'
7 |
8 | t.timestamps
9 | end
10 | add_index :users, :email, unique: true
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # This file is the source Rails uses to define your schema when running `rails
6 | # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
7 | # be faster and is potentially less error prone than running all of your
8 | # migrations from scratch. Old migrations may fail to apply correctly if those
9 | # migrations use external dependencies or application code.
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 2019_09_13_103805) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "users", force: :cascade do |t|
19 | t.string "email"
20 | t.string "password_digest"
21 | t.integer "role", default: 2, comment: "1. Admin 2. Customer"
22 | t.datetime "created_at", precision: 6, null: false
23 | t.datetime "updated_at", precision: 6, null: false
24 | t.index ["email"], name: "index_users_on_email", unique: true
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
7 | # Character.create(name: 'Luke', movie: movies.first)
8 |
9 | User.create([{ email: 'admin@test.com', password_digest: '$2a$12$keNVoKoKBLpSFJEituf9Leq3pOaW6hN2wum5ozuRtRSlZna2Uidwq', role: 1 }]) #password: 12345
10 | User.create([{ email: 'user@test.com', password_digest: '$2a$12$keNVoKoKBLpSFJEituf9Leq3pOaW6hN2wum5ozuRtRSlZna2Uidwq', role: 2 }])
11 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "railsvuejs",
3 | "private": true,
4 | "dependencies": {
5 | "@fortawesome/fontawesome": "^1.1.8",
6 | "@fortawesome/fontawesome-free-solid": "^5.0.13",
7 | "@rails/actioncable": "^6.0.0-alpha",
8 | "@rails/activestorage": "^6.0.0-alpha",
9 | "@rails/ujs": "^6.0.0-alpha",
10 | "@rails/webpacker": "^4.0.7",
11 | "axios": "^0.19.0",
12 | "i18n-js": "^3.3.0",
13 | "tailwind": "^4.0.0",
14 | "turbolinks": "^5.2.0",
15 | "vue": "^2.6.10",
16 | "vue-loader": "^15.7.1",
17 | "vue-template-compiler": "^2.6.10",
18 | "vue-turbolinks": "^2.0.4"
19 | },
20 | "version": "0.1.0",
21 | "devDependencies": {
22 | "tailwindcss": "^1.1.2",
23 | "webpack-dev-server": "^3.8.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('tailwindcss')('./app/javascript/css/tailwind.js'),
4 | require('autoprefixer'),
5 | require('postcss-import'),
6 | require('postcss-flexbugs-fixes'),
7 | require('postcss-preset-env')({
8 | autoprefixer: {
9 | flexbox: 'no-2009'
10 | },
11 | stage: 3
12 | })
13 | ]
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/public/favicon.ico
--------------------------------------------------------------------------------
/public/javascripts/i18n.js:
--------------------------------------------------------------------------------
1 | // I18n.js
2 | // =======
3 | //
4 | // This small library provides the Rails I18n API on the Javascript.
5 | // You don't actually have to use Rails (or even Ruby) to use I18n.js.
6 | // Just make sure you export all translations in an object like this:
7 | //
8 | // I18n.translations.en = {
9 | // hello: "Hello World"
10 | // };
11 | //
12 | // See tests for specific formatting like numbers and dates.
13 | //
14 |
15 | // Using UMD pattern from
16 | // https://github.com/umdjs/umd#regular-module
17 | // `returnExports.js` version
18 | ;(function (root, factory) {
19 | if (typeof define === 'function' && define.amd) {
20 | // AMD. Register as an anonymous module.
21 | define("i18n", function(){ return factory(root);});
22 | } else if (typeof module === 'object' && module.exports) {
23 | // Node. Does not work with strict CommonJS, but
24 | // only CommonJS-like environments that support module.exports,
25 | // like Node.
26 | module.exports = factory(root);
27 | } else {
28 | // Browser globals (root is window)
29 | root.I18n = factory(root);
30 | }
31 | }(this, function(global) {
32 | "use strict";
33 |
34 | // Use previously defined object if exists in current scope
35 | var I18n = global && global.I18n || {};
36 |
37 | // Just cache the Array#slice function.
38 | var slice = Array.prototype.slice;
39 |
40 | // Apply number padding.
41 | var padding = function(number) {
42 | return ("0" + number.toString()).substr(-2);
43 | };
44 |
45 | // Improved toFixed number rounding function with support for unprecise floating points
46 | // JavaScript's standard toFixed function does not round certain numbers correctly (for example 0.105 with precision 2).
47 | var toFixed = function(number, precision) {
48 | return decimalAdjust('round', number, -precision).toFixed(precision);
49 | };
50 |
51 | // Is a given variable an object?
52 | // Borrowed from Underscore.js
53 | var isObject = function(obj) {
54 | var type = typeof obj;
55 | return type === 'function' || type === 'object'
56 | };
57 |
58 | var isFunction = function(func) {
59 | var type = typeof func;
60 | return type === 'function'
61 | };
62 |
63 | // Check if value is different than undefined and null;
64 | var isSet = function(value) {
65 | return typeof(value) !== 'undefined' && value !== null;
66 | };
67 |
68 | // Is a given value an array?
69 | // Borrowed from Underscore.js
70 | var isArray = function(val) {
71 | if (Array.isArray) {
72 | return Array.isArray(val);
73 | }
74 | return Object.prototype.toString.call(val) === '[object Array]';
75 | };
76 |
77 | var isString = function(val) {
78 | return typeof val === 'string' || Object.prototype.toString.call(val) === '[object String]';
79 | };
80 |
81 | var isNumber = function(val) {
82 | return typeof val === 'number' || Object.prototype.toString.call(val) === '[object Number]';
83 | };
84 |
85 | var isBoolean = function(val) {
86 | return val === true || val === false;
87 | };
88 |
89 | var isNull = function(val) {
90 | return val === null;
91 | };
92 |
93 | var decimalAdjust = function(type, value, exp) {
94 | // If the exp is undefined or zero...
95 | if (typeof exp === 'undefined' || +exp === 0) {
96 | return Math[type](value);
97 | }
98 | value = +value;
99 | exp = +exp;
100 | // If the value is not a number or the exp is not an integer...
101 | if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
102 | return NaN;
103 | }
104 | // Shift
105 | value = value.toString().split('e');
106 | value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
107 | // Shift back
108 | value = value.toString().split('e');
109 | return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
110 | };
111 |
112 | var lazyEvaluate = function(message, scope) {
113 | if (isFunction(message)) {
114 | return message(scope);
115 | } else {
116 | return message;
117 | }
118 | };
119 |
120 | var merge = function (dest, obj) {
121 | var key, value;
122 | for (key in obj) if (obj.hasOwnProperty(key)) {
123 | value = obj[key];
124 | if (isString(value) || isNumber(value) || isBoolean(value) || isArray(value) || isNull(value)) {
125 | dest[key] = value;
126 | } else {
127 | if (dest[key] == null) dest[key] = {};
128 | merge(dest[key], value);
129 | }
130 | }
131 | return dest;
132 | };
133 |
134 | // Set default days/months translations.
135 | var DATE = {
136 | day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
137 | , abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
138 | , month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
139 | , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
140 | , meridian: ["AM", "PM"]
141 | };
142 |
143 | // Set default number format.
144 | var NUMBER_FORMAT = {
145 | precision: 3
146 | , separator: "."
147 | , delimiter: ","
148 | , strip_insignificant_zeros: false
149 | };
150 |
151 | // Set default currency format.
152 | var CURRENCY_FORMAT = {
153 | unit: "$"
154 | , precision: 2
155 | , format: "%u%n"
156 | , sign_first: true
157 | , delimiter: ","
158 | , separator: "."
159 | };
160 |
161 | // Set default percentage format.
162 | var PERCENTAGE_FORMAT = {
163 | unit: "%"
164 | , precision: 3
165 | , format: "%n%u"
166 | , separator: "."
167 | , delimiter: ""
168 | };
169 |
170 | // Set default size units.
171 | var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"];
172 |
173 | // Other default options
174 | var DEFAULT_OPTIONS = {
175 | // Set default locale. This locale will be used when fallback is enabled and
176 | // the translation doesn't exist in a particular locale.
177 | defaultLocale: "en"
178 | // Set the current locale to `en`.
179 | , locale: "en"
180 | // Set the translation key separator.
181 | , defaultSeparator: "."
182 | // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
183 | , placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm
184 | // Set if engine should fallback to the default locale when a translation
185 | // is missing.
186 | , fallbacks: false
187 | // Set the default translation object.
188 | , translations: {}
189 | // Set missing translation behavior. 'message' will display a message
190 | // that the translation is missing, 'guess' will try to guess the string
191 | , missingBehaviour: 'message'
192 | // if you use missingBehaviour with 'message', but want to know that the
193 | // string is actually missing for testing purposes, you can prefix the
194 | // guessed string by setting the value here. By default, no prefix!
195 | , missingTranslationPrefix: ''
196 | };
197 |
198 | // Set default locale. This locale will be used when fallback is enabled and
199 | // the translation doesn't exist in a particular locale.
200 | I18n.reset = function() {
201 | var key;
202 | for (key in DEFAULT_OPTIONS) {
203 | this[key] = DEFAULT_OPTIONS[key];
204 | }
205 | };
206 |
207 | // Much like `reset`, but only assign options if not already assigned
208 | I18n.initializeOptions = function() {
209 | var key;
210 | for (key in DEFAULT_OPTIONS) if (!isSet(this[key])) {
211 | this[key] = DEFAULT_OPTIONS[key];
212 | }
213 | };
214 | I18n.initializeOptions();
215 |
216 | // Return a list of all locales that must be tried before returning the
217 | // missing translation message. By default, this will consider the inline option,
218 | // current locale and fallback locale.
219 | //
220 | // I18n.locales.get("de-DE");
221 | // // ["de-DE", "de", "en"]
222 | //
223 | // You can define custom rules for any locale. Just make sure you return a array
224 | // containing all locales.
225 | //
226 | // // Default the Wookie locale to English.
227 | // I18n.locales["wk"] = function(locale) {
228 | // return ["en"];
229 | // };
230 | //
231 | I18n.locales = {};
232 |
233 | // Retrieve locales based on inline locale, current locale or default to
234 | // I18n's detection.
235 | I18n.locales.get = function(locale) {
236 | var result = this[locale] || this[I18n.locale] || this["default"];
237 |
238 | if (isFunction(result)) {
239 | result = result(locale);
240 | }
241 |
242 | if (isArray(result) === false) {
243 | result = [result];
244 | }
245 |
246 | return result;
247 | };
248 |
249 | // The default locale list.
250 | I18n.locales["default"] = function(locale) {
251 | var locales = []
252 | , list = []
253 | ;
254 |
255 | // Handle the inline locale option that can be provided to
256 | // the `I18n.t` options.
257 | if (locale) {
258 | locales.push(locale);
259 | }
260 |
261 | // Add the current locale to the list.
262 | if (!locale && I18n.locale) {
263 | locales.push(I18n.locale);
264 | }
265 |
266 | // Add the default locale if fallback strategy is enabled.
267 | if (I18n.fallbacks && I18n.defaultLocale) {
268 | locales.push(I18n.defaultLocale);
269 | }
270 |
271 | // Locale code format 1:
272 | // According to RFC4646 (http://www.ietf.org/rfc/rfc4646.txt)
273 | // language codes for Traditional Chinese should be `zh-Hant`
274 | //
275 | // But due to backward compatibility
276 | // We use older version of IETF language tag
277 | // @see http://www.w3.org/TR/html401/struct/dirlang.html
278 | // @see http://en.wikipedia.org/wiki/IETF_language_tag
279 | //
280 | // Format: `language-code = primary-code ( "-" subcode )*`
281 | //
282 | // primary-code uses ISO639-1
283 | // @see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
284 | // @see http://www.iso.org/iso/home/standards/language_codes.htm
285 | //
286 | // subcode uses ISO 3166-1 alpha-2
287 | // @see http://en.wikipedia.org/wiki/ISO_3166
288 | // @see http://www.iso.org/iso/country_codes.htm
289 | //
290 | // @note
291 | // subcode can be in upper case or lower case
292 | // defining it in upper case is a convention only
293 |
294 |
295 | // Locale code format 2:
296 | // Format: `code = primary-code ( "-" region-code )*`
297 | // primary-code uses ISO 639-1
298 | // script-code uses ISO 15924
299 | // region-code uses ISO 3166-1 alpha-2
300 | // Example: zh-Hant-TW, en-HK, zh-Hant-CN
301 | //
302 | // It is similar to RFC4646 (or actually the same),
303 | // but seems to be limited to language, script, region
304 |
305 | // Compute each locale with its country code.
306 | // So this will return an array containing
307 | // `de-DE` and `de`
308 | // or
309 | // `zh-hans-tw`, `zh-hans`, `zh`
310 | // locales.
311 | locales.forEach(function(locale) {
312 | var localeParts = locale.split("-");
313 | var firstFallback = null;
314 | var secondFallback = null;
315 | if (localeParts.length === 3) {
316 | firstFallback = [
317 | localeParts[0],
318 | localeParts[1]
319 | ].join("-");
320 | secondFallback = localeParts[0];
321 | }
322 | else if (localeParts.length === 2) {
323 | firstFallback = localeParts[0];
324 | }
325 |
326 | if (list.indexOf(locale) === -1) {
327 | list.push(locale);
328 | }
329 |
330 | if (! I18n.fallbacks) {
331 | return;
332 | }
333 |
334 | [
335 | firstFallback,
336 | secondFallback
337 | ].forEach(function(nullableFallbackLocale) {
338 | // We don't want null values
339 | if (typeof nullableFallbackLocale === "undefined") { return; }
340 | if (nullableFallbackLocale === null) { return; }
341 | // We don't want duplicate values
342 | //
343 | // Comparing with `locale` first is faster than
344 | // checking whether value's presence in the list
345 | if (nullableFallbackLocale === locale) { return; }
346 | if (list.indexOf(nullableFallbackLocale) !== -1) { return; }
347 |
348 | list.push(nullableFallbackLocale);
349 | });
350 | });
351 |
352 | // No locales set? English it is.
353 | if (!locales.length) {
354 | locales.push("en");
355 | }
356 |
357 | return list;
358 | };
359 |
360 | // Hold pluralization rules.
361 | I18n.pluralization = {};
362 |
363 | // Return the pluralizer for a specific locale.
364 | // If no specify locale is found, then I18n's default will be used.
365 | I18n.pluralization.get = function(locale) {
366 | return this[locale] || this[I18n.locale] || this["default"];
367 | };
368 |
369 | // The default pluralizer rule.
370 | // It detects the `zero`, `one`, and `other` scopes.
371 | I18n.pluralization["default"] = function(count) {
372 | switch (count) {
373 | case 0: return ["zero", "other"];
374 | case 1: return ["one"];
375 | default: return ["other"];
376 | }
377 | };
378 |
379 | // Return current locale. If no locale has been set, then
380 | // the current locale will be the default locale.
381 | I18n.currentLocale = function() {
382 | return this.locale || this.defaultLocale;
383 | };
384 |
385 | // Check if value is different than undefined and null;
386 | I18n.isSet = isSet;
387 |
388 | // Find and process the translation using the provided scope and options.
389 | // This is used internally by some functions and should not be used as an
390 | // public API.
391 | I18n.lookup = function(scope, options) {
392 | options = options || {};
393 |
394 | var locales = this.locales.get(options.locale).slice()
395 | , locale
396 | , scopes
397 | , fullScope
398 | , translations
399 | ;
400 |
401 | fullScope = this.getFullScope(scope, options);
402 |
403 | while (locales.length) {
404 | locale = locales.shift();
405 | scopes = fullScope.split(this.defaultSeparator);
406 | translations = this.translations[locale];
407 |
408 | if (!translations) {
409 | continue;
410 | }
411 | while (scopes.length) {
412 | translations = translations[scopes.shift()];
413 |
414 | if (translations === undefined || translations === null) {
415 | break;
416 | }
417 | }
418 |
419 | if (translations !== undefined && translations !== null) {
420 | return translations;
421 | }
422 | }
423 |
424 | if (isSet(options.defaultValue)) {
425 | return lazyEvaluate(options.defaultValue, scope);
426 | }
427 | };
428 |
429 | // lookup pluralization rule key into translations
430 | I18n.pluralizationLookupWithoutFallback = function(count, locale, translations) {
431 | var pluralizer = this.pluralization.get(locale)
432 | , pluralizerKeys = pluralizer(count)
433 | , pluralizerKey
434 | , message;
435 |
436 | if (isObject(translations)) {
437 | while (pluralizerKeys.length) {
438 | pluralizerKey = pluralizerKeys.shift();
439 | if (isSet(translations[pluralizerKey])) {
440 | message = translations[pluralizerKey];
441 | break;
442 | }
443 | }
444 | }
445 |
446 | return message;
447 | };
448 |
449 | // Lookup dedicated to pluralization
450 | I18n.pluralizationLookup = function(count, scope, options) {
451 | options = options || {};
452 | var locales = this.locales.get(options.locale).slice()
453 | , locale
454 | , scopes
455 | , translations
456 | , message
457 | ;
458 | scope = this.getFullScope(scope, options);
459 |
460 | while (locales.length) {
461 | locale = locales.shift();
462 | scopes = scope.split(this.defaultSeparator);
463 | translations = this.translations[locale];
464 |
465 | if (!translations) {
466 | continue;
467 | }
468 |
469 | while (scopes.length) {
470 | translations = translations[scopes.shift()];
471 | if (!isObject(translations)) {
472 | break;
473 | }
474 | if (scopes.length === 0) {
475 | message = this.pluralizationLookupWithoutFallback(count, locale, translations);
476 | }
477 | }
478 | if (typeof message !== "undefined" && message !== null) {
479 | break;
480 | }
481 | }
482 |
483 | if (typeof message === "undefined" || message === null) {
484 | if (isSet(options.defaultValue)) {
485 | if (isObject(options.defaultValue)) {
486 | message = this.pluralizationLookupWithoutFallback(count, options.locale, options.defaultValue);
487 | } else {
488 | message = options.defaultValue;
489 | }
490 | translations = options.defaultValue;
491 | }
492 | }
493 |
494 | return { message: message, translations: translations };
495 | };
496 |
497 | // Rails changed the way the meridian is stored.
498 | // It started with `date.meridian` returning an array,
499 | // then it switched to `time.am` and `time.pm`.
500 | // This function abstracts this difference and returns
501 | // the correct meridian or the default value when none is provided.
502 | I18n.meridian = function() {
503 | var time = this.lookup("time");
504 | var date = this.lookup("date");
505 |
506 | if (time && time.am && time.pm) {
507 | return [time.am, time.pm];
508 | } else if (date && date.meridian) {
509 | return date.meridian;
510 | } else {
511 | return DATE.meridian;
512 | }
513 | };
514 |
515 | // Merge serveral hash options, checking if value is set before
516 | // overwriting any value. The precedence is from left to right.
517 | //
518 | // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
519 | // #=> {name: "John Doe", role: "user"}
520 | //
521 | I18n.prepareOptions = function() {
522 | var args = slice.call(arguments)
523 | , options = {}
524 | , subject
525 | ;
526 |
527 | while (args.length) {
528 | subject = args.shift();
529 |
530 | if (typeof(subject) != "object") {
531 | continue;
532 | }
533 |
534 | for (var attr in subject) {
535 | if (!subject.hasOwnProperty(attr)) {
536 | continue;
537 | }
538 |
539 | if (isSet(options[attr])) {
540 | continue;
541 | }
542 |
543 | options[attr] = subject[attr];
544 | }
545 | }
546 |
547 | return options;
548 | };
549 |
550 | // Generate a list of translation options for default fallbacks.
551 | // `defaultValue` is also deleted from options as it is returned as part of
552 | // the translationOptions array.
553 | I18n.createTranslationOptions = function(scope, options) {
554 | var translationOptions = [{scope: scope}];
555 |
556 | // Defaults should be an array of hashes containing either
557 | // fallback scopes or messages
558 | if (isSet(options.defaults)) {
559 | translationOptions = translationOptions.concat(options.defaults);
560 | }
561 |
562 | // Maintain support for defaultValue. Since it is always a message
563 | // insert it in to the translation options as such.
564 | if (isSet(options.defaultValue)) {
565 | translationOptions.push({ message: options.defaultValue });
566 | }
567 |
568 | return translationOptions;
569 | };
570 |
571 | // Translate the given scope with the provided options.
572 | I18n.translate = function(scope, options) {
573 | options = options || {};
574 |
575 | var translationOptions = this.createTranslationOptions(scope, options);
576 |
577 | var translation;
578 | var usedScope = scope;
579 |
580 | var optionsWithoutDefault = this.prepareOptions(options)
581 | delete optionsWithoutDefault.defaultValue
582 |
583 | // Iterate through the translation options until a translation
584 | // or message is found.
585 | var translationFound =
586 | translationOptions.some(function(translationOption) {
587 | if (isSet(translationOption.scope)) {
588 | usedScope = translationOption.scope;
589 | translation = this.lookup(usedScope, optionsWithoutDefault);
590 | } else if (isSet(translationOption.message)) {
591 | translation = lazyEvaluate(translationOption.message, scope);
592 | }
593 |
594 | if (translation !== undefined && translation !== null) {
595 | return true;
596 | }
597 | }, this);
598 |
599 | if (!translationFound) {
600 | return this.missingTranslation(scope, options);
601 | }
602 |
603 | if (typeof(translation) === "string") {
604 | translation = this.interpolate(translation, options);
605 | } else if (isArray(translation)) {
606 | translation = translation.map(function(t) {
607 | return (typeof(t) === "string" ? this.interpolate(t, options) : t);
608 | }, this);
609 | } else if (isObject(translation) && isSet(options.count)) {
610 | translation = this.pluralize(options.count, usedScope, options);
611 | }
612 |
613 | return translation;
614 | };
615 |
616 | // This function interpolates the all variables in the given message.
617 | I18n.interpolate = function(message, options) {
618 | if (message == null) {
619 | return message;
620 | }
621 |
622 | options = options || {};
623 | var matches = message.match(this.placeholder)
624 | , placeholder
625 | , value
626 | , name
627 | , regex
628 | ;
629 |
630 | if (!matches) {
631 | return message;
632 | }
633 |
634 | while (matches.length) {
635 | placeholder = matches.shift();
636 | name = placeholder.replace(this.placeholder, "$1");
637 |
638 | if (isSet(options[name])) {
639 | value = options[name].toString().replace(/\$/gm, "_#$#_");
640 | } else if (name in options) {
641 | value = this.nullPlaceholder(placeholder, message, options);
642 | } else {
643 | value = this.missingPlaceholder(placeholder, message, options);
644 | }
645 |
646 | regex = new RegExp(placeholder.replace(/{/gm, "\\{").replace(/}/gm, "\\}"));
647 | message = message.replace(regex, value);
648 | }
649 |
650 | return message.replace(/_#\$#_/g, "$");
651 | };
652 |
653 | // Pluralize the given scope using the `count` value.
654 | // The pluralized translation may have other placeholders,
655 | // which will be retrieved from `options`.
656 | I18n.pluralize = function(count, scope, options) {
657 | options = this.prepareOptions({count: String(count)}, options)
658 | var pluralizer, result;
659 |
660 | result = this.pluralizationLookup(count, scope, options);
661 | if (typeof result.translations === "undefined" || result.translations == null) {
662 | return this.missingTranslation(scope, options);
663 | }
664 |
665 | if (typeof result.message !== "undefined" && result.message != null) {
666 | return this.interpolate(result.message, options);
667 | }
668 | else {
669 | pluralizer = this.pluralization.get(options.locale);
670 | return this.missingTranslation(scope + '.' + pluralizer(count)[0], options);
671 | }
672 | };
673 |
674 | // Return a missing translation message for the given parameters.
675 | I18n.missingTranslation = function(scope, options) {
676 | //guess intended string
677 | if(this.missingBehaviour === 'guess'){
678 | //get only the last portion of the scope
679 | var s = scope.split('.').slice(-1)[0];
680 | //replace underscore with space && camelcase with space and lowercase letter
681 | return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') +
682 | s.replace('_',' ').replace(/([a-z])([A-Z])/g,
683 | function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} );
684 | }
685 |
686 | var localeForTranslation = (options != null && options.locale != null) ? options.locale : this.currentLocale();
687 | var fullScope = this.getFullScope(scope, options);
688 | var fullScopeWithLocale = [localeForTranslation, fullScope].join(this.defaultSeparator);
689 |
690 | return '[missing "' + fullScopeWithLocale + '" translation]';
691 | };
692 |
693 | // Return a missing placeholder message for given parameters
694 | I18n.missingPlaceholder = function(placeholder, message, options) {
695 | return "[missing " + placeholder + " value]";
696 | };
697 |
698 | I18n.nullPlaceholder = function() {
699 | return I18n.missingPlaceholder.apply(I18n, arguments);
700 | };
701 |
702 | // Format number using localization rules.
703 | // The options will be retrieved from the `number.format` scope.
704 | // If this isn't present, then the following options will be used:
705 | //
706 | // - `precision`: `3`
707 | // - `separator`: `"."`
708 | // - `delimiter`: `","`
709 | // - `strip_insignificant_zeros`: `false`
710 | //
711 | // You can also override these options by providing the `options` argument.
712 | //
713 | I18n.toNumber = function(number, options) {
714 | options = this.prepareOptions(
715 | options
716 | , this.lookup("number.format")
717 | , NUMBER_FORMAT
718 | );
719 |
720 | var negative = number < 0
721 | , string = toFixed(Math.abs(number), options.precision).toString()
722 | , parts = string.split(".")
723 | , precision
724 | , buffer = []
725 | , formattedNumber
726 | , format = options.format || "%n"
727 | , sign = negative ? "-" : ""
728 | ;
729 |
730 | number = parts[0];
731 | precision = parts[1];
732 |
733 | while (number.length > 0) {
734 | buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
735 | number = number.substr(0, number.length -3);
736 | }
737 |
738 | formattedNumber = buffer.join(options.delimiter);
739 |
740 | if (options.strip_insignificant_zeros && precision) {
741 | precision = precision.replace(/0+$/, "");
742 | }
743 |
744 | if (options.precision > 0 && precision) {
745 | formattedNumber += options.separator + precision;
746 | }
747 |
748 | if (options.sign_first) {
749 | format = "%s" + format;
750 | }
751 | else {
752 | format = format.replace("%n", "%s%n");
753 | }
754 |
755 | formattedNumber = format
756 | .replace("%u", options.unit)
757 | .replace("%n", formattedNumber)
758 | .replace("%s", sign)
759 | ;
760 |
761 | return formattedNumber;
762 | };
763 |
764 | // Format currency with localization rules.
765 | // The options will be retrieved from the `number.currency.format` and
766 | // `number.format` scopes, in that order.
767 | //
768 | // Any missing option will be retrieved from the `I18n.toNumber` defaults and
769 | // the following options:
770 | //
771 | // - `unit`: `"$"`
772 | // - `precision`: `2`
773 | // - `format`: `"%u%n"`
774 | // - `delimiter`: `","`
775 | // - `separator`: `"."`
776 | //
777 | // You can also override these options by providing the `options` argument.
778 | //
779 | I18n.toCurrency = function(number, options) {
780 | options = this.prepareOptions(
781 | options
782 | , this.lookup("number.currency.format")
783 | , this.lookup("number.format")
784 | , CURRENCY_FORMAT
785 | );
786 |
787 | return this.toNumber(number, options);
788 | };
789 |
790 | // Localize several values.
791 | // You can provide the following scopes: `currency`, `number`, or `percentage`.
792 | // If you provide a scope that matches the `/^(date|time)/` regular expression
793 | // then the `value` will be converted by using the `I18n.toTime` function.
794 | //
795 | // It will default to the value's `toString` function.
796 | //
797 | I18n.localize = function(scope, value, options) {
798 | options || (options = {});
799 |
800 | switch (scope) {
801 | case "currency":
802 | return this.toCurrency(value);
803 | case "number":
804 | scope = this.lookup("number.format");
805 | return this.toNumber(value, scope);
806 | case "percentage":
807 | return this.toPercentage(value);
808 | default:
809 | var localizedValue;
810 |
811 | if (scope.match(/^(date|time)/)) {
812 | localizedValue = this.toTime(scope, value);
813 | } else {
814 | localizedValue = value.toString();
815 | }
816 |
817 | return this.interpolate(localizedValue, options);
818 | }
819 | };
820 |
821 | // Parse a given `date` string into a JavaScript Date object.
822 | // This function is time zone aware.
823 | //
824 | // The following string formats are recognized:
825 | //
826 | // yyyy-mm-dd
827 | // yyyy-mm-dd[ T]hh:mm::ss
828 | // yyyy-mm-dd[ T]hh:mm::ss
829 | // yyyy-mm-dd[ T]hh:mm::ssZ
830 | // yyyy-mm-dd[ T]hh:mm::ss+0000
831 | // yyyy-mm-dd[ T]hh:mm::ss+00:00
832 | // yyyy-mm-dd[ T]hh:mm::ss.123Z
833 | //
834 | I18n.parseDate = function(date) {
835 | var matches, convertedDate, fraction;
836 | // A date input of `null` or `undefined` will be returned as-is
837 | if (date == null) {
838 | return date;
839 | }
840 | // we have a date, so just return it.
841 | if (typeof(date) === "object") {
842 | return date;
843 | }
844 |
845 | matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/);
846 |
847 | if (matches) {
848 | for (var i = 1; i <= 6; i++) {
849 | matches[i] = parseInt(matches[i], 10) || 0;
850 | }
851 |
852 | // month starts on 0
853 | matches[2] -= 1;
854 |
855 | fraction = matches[7] ? 1000 * ("0" + matches[7]) : null;
856 |
857 | if (matches[8]) {
858 | convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction));
859 | } else {
860 | convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction);
861 | }
862 | } else if (typeof(date) == "number") {
863 | // UNIX timestamp
864 | convertedDate = new Date();
865 | convertedDate.setTime(date);
866 | } else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) {
867 | // This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by
868 | // webkit/firefox, but not by IE, so we must parse it manually.
869 | convertedDate = new Date();
870 | convertedDate.setTime(Date.parse([
871 | RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5
872 | ].join(" ")));
873 | } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
874 | // a valid javascript format with timezone info
875 | convertedDate = new Date();
876 | convertedDate.setTime(Date.parse(date));
877 | } else {
878 | // an arbitrary javascript string
879 | convertedDate = new Date();
880 | convertedDate.setTime(Date.parse(date));
881 | }
882 |
883 | return convertedDate;
884 | };
885 |
886 | // Formats time according to the directives in the given format string.
887 | // The directives begins with a percent (%) character. Any text not listed as a
888 | // directive will be passed through to the output string.
889 | //
890 | // The accepted formats are:
891 | //
892 | // %a - The abbreviated weekday name (Sun)
893 | // %A - The full weekday name (Sunday)
894 | // %b - The abbreviated month name (Jan)
895 | // %B - The full month name (January)
896 | // %c - The preferred local date and time representation
897 | // %d - Day of the month (01..31)
898 | // %-d - Day of the month (1..31)
899 | // %H - Hour of the day, 24-hour clock (00..23)
900 | // %-H/%k - Hour of the day, 24-hour clock (0..23)
901 | // %I - Hour of the day, 12-hour clock (01..12)
902 | // %-I/%l - Hour of the day, 12-hour clock (1..12)
903 | // %m - Month of the year (01..12)
904 | // %-m - Month of the year (1..12)
905 | // %M - Minute of the hour (00..59)
906 | // %-M - Minute of the hour (0..59)
907 | // %p - Meridian indicator (AM or PM)
908 | // %P - Meridian indicator (am or pm)
909 | // %S - Second of the minute (00..60)
910 | // %-S - Second of the minute (0..60)
911 | // %w - Day of the week (Sunday is 0, 0..6)
912 | // %y - Year without a century (00..99)
913 | // %-y - Year without a century (0..99)
914 | // %Y - Year with century
915 | // %z/%Z - Timezone offset (+0545)
916 | //
917 | I18n.strftime = function(date, format) {
918 | var options = this.lookup("date")
919 | , meridianOptions = I18n.meridian()
920 | ;
921 |
922 | if (!options) {
923 | options = {};
924 | }
925 |
926 | options = this.prepareOptions(options, DATE);
927 |
928 | if (isNaN(date.getTime())) {
929 | throw new Error('I18n.strftime() requires a valid date object, but received an invalid date.');
930 | }
931 |
932 | var weekDay = date.getDay()
933 | , day = date.getDate()
934 | , year = date.getFullYear()
935 | , month = date.getMonth() + 1
936 | , hour = date.getHours()
937 | , hour12 = hour
938 | , meridian = hour > 11 ? 1 : 0
939 | , secs = date.getSeconds()
940 | , mins = date.getMinutes()
941 | , offset = date.getTimezoneOffset()
942 | , absOffsetHours = Math.floor(Math.abs(offset / 60))
943 | , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
944 | , timezoneoffset = (offset > 0 ? "-" : "+") +
945 | (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) +
946 | (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
947 | ;
948 |
949 | if (hour12 > 12) {
950 | hour12 = hour12 - 12;
951 | } else if (hour12 === 0) {
952 | hour12 = 12;
953 | }
954 |
955 | format = format.replace("%a", options.abbr_day_names[weekDay]);
956 | format = format.replace("%A", options.day_names[weekDay]);
957 | format = format.replace("%b", options.abbr_month_names[month]);
958 | format = format.replace("%B", options.month_names[month]);
959 | format = format.replace("%d", padding(day));
960 | format = format.replace("%e", day);
961 | format = format.replace("%-d", day);
962 | format = format.replace("%H", padding(hour));
963 | format = format.replace("%-H", hour);
964 | format = format.replace("%k", hour);
965 | format = format.replace("%I", padding(hour12));
966 | format = format.replace("%-I", hour12);
967 | format = format.replace("%l", hour12);
968 | format = format.replace("%m", padding(month));
969 | format = format.replace("%-m", month);
970 | format = format.replace("%M", padding(mins));
971 | format = format.replace("%-M", mins);
972 | format = format.replace("%p", meridianOptions[meridian]);
973 | format = format.replace("%P", meridianOptions[meridian].toLowerCase());
974 | format = format.replace("%S", padding(secs));
975 | format = format.replace("%-S", secs);
976 | format = format.replace("%w", weekDay);
977 | format = format.replace("%y", padding(year));
978 | format = format.replace("%-y", padding(year).replace(/^0+/, ""));
979 | format = format.replace("%Y", year);
980 | format = format.replace("%z", timezoneoffset);
981 | format = format.replace("%Z", timezoneoffset);
982 |
983 | return format;
984 | };
985 |
986 | // Convert the given dateString into a formatted date.
987 | I18n.toTime = function(scope, dateString) {
988 | var date = this.parseDate(dateString)
989 | , format = this.lookup(scope)
990 | ;
991 |
992 | // A date input of `null` or `undefined` will be returned as-is
993 | if (date == null) {
994 | return date;
995 | }
996 |
997 | var date_string = date.toString()
998 | if (date_string.match(/invalid/i)) {
999 | return date_string;
1000 | }
1001 |
1002 | if (!format) {
1003 | return date_string;
1004 | }
1005 |
1006 | return this.strftime(date, format);
1007 | };
1008 |
1009 | // Convert a number into a formatted percentage value.
1010 | I18n.toPercentage = function(number, options) {
1011 | options = this.prepareOptions(
1012 | options
1013 | , this.lookup("number.percentage.format")
1014 | , this.lookup("number.format")
1015 | , PERCENTAGE_FORMAT
1016 | );
1017 |
1018 | return this.toNumber(number, options);
1019 | };
1020 |
1021 | // Convert a number into a readable size representation.
1022 | I18n.toHumanSize = function(number, options) {
1023 | var kb = 1024
1024 | , size = number
1025 | , iterations = 0
1026 | , unit
1027 | , precision
1028 | ;
1029 |
1030 | while (size >= kb && iterations < 4) {
1031 | size = size / kb;
1032 | iterations += 1;
1033 | }
1034 |
1035 | if (iterations === 0) {
1036 | unit = this.t("number.human.storage_units.units.byte", {count: size});
1037 | precision = 0;
1038 | } else {
1039 | unit = this.t("number.human.storage_units.units." + SIZE_UNITS[iterations]);
1040 | precision = (size - Math.floor(size) === 0) ? 0 : 1;
1041 | }
1042 |
1043 | options = this.prepareOptions(
1044 | options
1045 | , {unit: unit, precision: precision, format: "%n%u", delimiter: ""}
1046 | );
1047 |
1048 | return this.toNumber(size, options);
1049 | };
1050 |
1051 | I18n.getFullScope = function(scope, options) {
1052 | options = options || {};
1053 |
1054 | // Deal with the scope as an array.
1055 | if (isArray(scope)) {
1056 | scope = scope.join(this.defaultSeparator);
1057 | }
1058 |
1059 | // Deal with the scope option provided through the second argument.
1060 | //
1061 | // I18n.t('hello', {scope: 'greetings'});
1062 | //
1063 | if (options.scope) {
1064 | scope = [options.scope, scope].join(this.defaultSeparator);
1065 | }
1066 |
1067 | return scope;
1068 | };
1069 | /**
1070 | * Merge obj1 with obj2 (shallow merge), without modifying inputs
1071 | * @param {Object} obj1
1072 | * @param {Object} obj2
1073 | * @returns {Object} Merged values of obj1 and obj2
1074 | *
1075 | * In order to support ES3, `Object.prototype.hasOwnProperty.call` is used
1076 | * Idea is from:
1077 | * https://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8
1078 | */
1079 | I18n.extend = function ( obj1, obj2 ) {
1080 | if (typeof(obj1) === "undefined" && typeof(obj2) === "undefined") {
1081 | return {};
1082 | }
1083 | return merge(obj1, obj2);
1084 | };
1085 |
1086 | // Set aliases, so we can save some typing.
1087 | I18n.t = I18n.translate.bind(I18n);
1088 | I18n.l = I18n.localize.bind(I18n);
1089 | I18n.p = I18n.pluralize.bind(I18n);
1090 |
1091 | return I18n;
1092 | }));
1093 |
--------------------------------------------------------------------------------
/public/javascripts/translations.js:
--------------------------------------------------------------------------------
1 | import I18n from './i18n'
2 | I18n.translations || (I18n.translations = {});
3 | I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"activerecord":{"errors":{"messages":{"record_invalid":"Validation failed: %{errors}","restrict_dependent_destroy":{"has_many":"Cannot delete record because dependent %{record} exist","has_one":"Cannot delete record because a dependent %{record} exists"}}}},"attention":"Attention","cabinet":"Account","confirm_password":"Confirm password","control_panel":"Dashboard","date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"],"order":["year","month","day"]},"datetime":{"distance_in_words":{"about_x_hours":{"one":"about 1 hour","other":"about %{count} hours"},"about_x_months":{"one":"about 1 month","other":"about %{count} months"},"about_x_years":{"one":"about 1 year","other":"about %{count} years"},"almost_x_years":{"one":"almost 1 year","other":"almost %{count} years"},"half_a_minute":"half a minute","less_than_x_minutes":{"one":"less than a minute","other":"less than %{count} minutes"},"less_than_x_seconds":{"one":"less than 1 second","other":"less than %{count} seconds"},"over_x_years":{"one":"over 1 year","other":"over %{count} years"},"x_days":{"one":"1 day","other":"%{count} days"},"x_minutes":{"one":"1 minute","other":"%{count} minutes"},"x_months":{"one":"1 month","other":"%{count} months"},"x_seconds":{"one":"1 second","other":"%{count} seconds"}},"prompts":{"day":"Day","hour":"Hour","minute":"Minute","month":"Month","second":"Seconds","year":"Year"}},"email_or_password_wrong":"The specified e-mail is not registered, or the password is incorrect","enter":"Enter","enter_cabinet":"Enter in account","errors":{"connection_refused":"Oops! Failed to connect to the Web Console middleware.\nPlease make sure a rails development server is running.\n","format":"%{attribute} %{message}","messages":{"accepted":"must be accepted","blank":"can't be blank","confirmation":"doesn't match %{attribute}","empty":"can't be empty","equal_to":"must be equal to %{count}","even":"must be even","exclusion":"is reserved","greater_than":"must be greater than %{count}","greater_than_or_equal_to":"must be greater than or equal to %{count}","inclusion":"is not included in the list","invalid":"is invalid","less_than":"must be less than %{count}","less_than_or_equal_to":"must be less than or equal to %{count}","model_invalid":"Validation failed: %{errors}","not_a_number":"is not a number","not_an_integer":"must be an integer","odd":"must be odd","other_than":"must be other than %{count}","present":"must be blank","required":"must exist","taken":"has already been taken","too_long":{"one":"is too long (maximum is 1 character)","other":"is too long (maximum is %{count} characters)"},"too_short":{"one":"is too short (minimum is 1 character)","other":"is too short (minimum is %{count} characters)"},"wrong_length":{"one":"is the wrong length (should be 1 character)","other":"is the wrong length (should be %{count} characters)"}},"unacceptable_request":"A supported version is expected in the Accept header.\n","unavailable_session":"Session %{id} is no longer available in memory.\n\nIf you happen to run on a multi-process server (like Unicorn or Puma) the process\nthis request hit doesn't store %{id} in memory. Consider turning the number of\nprocesses/workers to one (1) or using a different server in development.\n"},"exit":"Exit","forgot_password":"Forgot password?","helpers":{"select":{"prompt":"Please select"},"submit":{"create":"Create %{model}","submit":"Save %{model}","update":"Update %{model}"}},"language":"Language","number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","significant":false,"strip_insignificant_zeros":false,"unit":"$"}},"format":{"delimiter":",","precision":3,"separator":".","significant":false,"strip_insignificant_zeros":false},"human":{"decimal_units":{"format":"%n %u","units":{"billion":"Billion","million":"Million","quadrillion":"Quadrillion","thousand":"Thousand","trillion":"Trillion","unit":""}},"format":{"delimiter":"","precision":3,"significant":true,"strip_insignificant_zeros":true},"storage_units":{"format":"%n %u","units":{"byte":{"one":"Byte","other":"Bytes"},"eb":"EB","gb":"GB","kb":"KB","mb":"MB","pb":"PB","tb":"TB"}}},"nth":{"ordinalized":{},"ordinals":{}},"percentage":{"format":{"delimiter":"","format":"%n%"}},"precision":{"format":{"delimiter":""}}},"password":"Password","register":"Registration","remember_me":"Remember","save":"Save","support":{"array":{"last_word_connector":", and ","two_words_connector":" and ","words_connector":", "}},"text":"Text","time":{"am":"am","formats":{"default":"%a, %d %b %Y %H:%M:%S %z","long":"%B %d, %Y %H:%M","short":"%d %b %H:%M"},"pm":"pm"},"user_registered":"User successfully registered"});
4 | I18n.translations["ru"] = I18n.extend((I18n.translations["ru"] || {}), {"attention":"Внимание","cabinet":"Кабинет","confirm_password":"Подтвердите пароль","control_panel":"Панель управления","email_or_password_wrong":"Указанный e-mail не зарегистрирован, либо указан неверный пароль","enter":"Вход","enter_cabinet":"Вход в кабинет","exit":"Выход","forgot_password":"Забыли пароль?","language":"Язык","password":"Пароль","register":"Регистрация","remember_me":"Запомнить","save":"Сохранить","text":"Текст","user_registered":"Пользователь успешно зарегистрирован"});
5 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/storage/.keep
--------------------------------------------------------------------------------
/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5 | end
6 |
--------------------------------------------------------------------------------
/test/channels/application_cable/connection_test.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
4 | # test "connects with cookies" do
5 | # cookies.signed[:user_id] = 42
6 | #
7 | # connect
8 | #
9 | # assert_equal connection.user_id, "42"
10 | # end
11 | end
12 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/landing_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class LandingControllerTest < ActionDispatch::IntegrationTest
4 | test "should get index" do
5 | get landing_index_url
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/test/controllers/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionDispatch::IntegrationTest
4 | test "should get new" do
5 | get sessions_new_url
6 | assert_response :success
7 | end
8 |
9 | test "should get create" do
10 | get sessions_create_url
11 | assert_response :success
12 | end
13 |
14 | test "should get destroy" do
15 | get sessions_destroy_url
16 | assert_response :success
17 | end
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/test/controllers/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersControllerTest < ActionDispatch::IntegrationTest
4 | setup do
5 | @user = users(:one)
6 | end
7 |
8 | test "should get index" do
9 | get users_url
10 | assert_response :success
11 | end
12 |
13 | test "should get new" do
14 | get new_user_url
15 | assert_response :success
16 | end
17 |
18 | test "should create user" do
19 | assert_difference('User.count') do
20 | post users_url, params: { user: { email: @user.email, password: 'secret', password_confirmation: 'secret' } }
21 | end
22 |
23 | assert_redirected_to user_url(User.last)
24 | end
25 |
26 | test "should show user" do
27 | get user_url(@user)
28 | assert_response :success
29 | end
30 |
31 | test "should get edit" do
32 | get edit_user_url(@user)
33 | assert_response :success
34 | end
35 |
36 | test "should update user" do
37 | patch user_url(@user), params: { user: { email: @user.email, password: 'secret', password_confirmation: 'secret' } }
38 | assert_redirected_to user_url(@user)
39 | end
40 |
41 | test "should destroy user" do
42 | assert_difference('User.count', -1) do
43 | delete user_url(@user)
44 | end
45 |
46 | assert_redirected_to users_url
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | email: MyString
5 | password_digest: <%= BCrypt::Password.create('secret') %>
6 |
7 | two:
8 | email: MyString
9 | password_digest: <%= BCrypt::Password.create('secret') %>
10 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/models/.keep
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/test/system/.keep
--------------------------------------------------------------------------------
/test/system/users_test.rb:
--------------------------------------------------------------------------------
1 | require "application_system_test_case"
2 |
3 | class UsersTest < ApplicationSystemTestCase
4 | setup do
5 | @user = users(:one)
6 | end
7 |
8 | test "visiting the index" do
9 | visit users_url
10 | assert_selector "h1", text: "Users"
11 | end
12 |
13 | test "creating a User" do
14 | visit users_url
15 | click_on "New User"
16 |
17 | fill_in "Email", with: @user.email
18 | fill_in "Password", with: 'secret'
19 | fill_in "Password confirmation", with: 'secret'
20 | click_on "Create User"
21 |
22 | assert_text "User was successfully created"
23 | click_on "Back"
24 | end
25 |
26 | test "updating a User" do
27 | visit users_url
28 | click_on "Edit", match: :first
29 |
30 | fill_in "Email", with: @user.email
31 | fill_in "Password", with: 'secret'
32 | fill_in "Password confirmation", with: 'secret'
33 | click_on "Update User"
34 |
35 | assert_text "User was successfully updated"
36 | click_on "Back"
37 | end
38 |
39 | test "destroying a User" do
40 | visit users_url
41 | page.accept_confirm do
42 | click_on "Destroy", match: :first
43 | end
44 |
45 | assert_text "User was successfully destroyed"
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require_relative '../config/environment'
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Run tests in parallel with specified workers
7 | parallelize(workers: :number_of_processors)
8 |
9 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
10 | fixtures :all
11 |
12 | # Add more helper methods to be used by all tests here...
13 | end
14 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/tmp/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medk0v/rails-vue-starter-kit/04d590d2860d0d30e19095b0a6f1994ce19564df/vendor/.keep
--------------------------------------------------------------------------------