This commit is contained in:
Dan Elbert 2018-03-30 14:31:09 -05:00
parent 98a204ab59
commit bb223af9ae
28 changed files with 464 additions and 74 deletions

View File

@ -1,5 +1,7 @@
.git/
logs/*.*
log/*.*
db/*.sqlite*
tmp/*.*
public/assets
public/packs
node_modules/

View File

@ -1,3 +1,7 @@
plugins:
postcss-import: {}
postcss-cssnext: {}
postcss-cssnext: {
features: {
customProperties: false
}
}

View File

@ -1 +1 @@
2.5.1
2.5.0

View File

@ -3,6 +3,16 @@ FROM phusion/passenger-ruby25:latest
# Use baseimage-docker's init process.
CMD ["/sbin/my_init"]
# Install Node
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list && \
apt-get update && \
apt-get install -y --no-install-recommends nodejs yarn && \
apt-get clean && rm -rf /var/lib/apt/lists/*
RUN gem update --system && gem install bundler
# Enable Nginx / Passenger
RUN rm -f /etc/service/nginx/down
@ -21,25 +31,20 @@ ENV RAILS_ENV docker
ENV PASSENGER_APP_ENV docker
# Setup directory and install gems
RUN mkdir -p /home/app/parsley/
COPY Gemfile /home/app/parsley/
COPY Gemfile.lock /home/app/parsley/
RUN gem install bundler
RUN cd /home/app/parsley/ && bundle install --jobs 4
# Copy the app into the image
COPY . /home/app/parsley/
RUN mkdir -p /home/app/parsley/log /home/app/parsley/tmp
RUN chown -R app:app /home/app/parsley/
WORKDIR /home/app/parsley/
# Set log permissions
RUN mkdir -p /home/app/parsley/log
RUN chmod 0777 /home/app/parsley/log
COPY Gemfile* ./
RUN bundle install --deployment --jobs 4 --without development test
COPY package.json yarn.lock ./
RUN yarn install --production=true
# Copy the app into the image
COPY --chown="app" . .
# Compile assets
RUN env RAILS_ENV=production bundle exec rake assets:clobber assets:precompile
RUN su app -c "bundle exec rails webpacker:clobber webpacker:compile"
# Set ownership of the tmp folder
RUN chown -R app:app /home/app/parsley/tmp
# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

10
Gemfile
View File

@ -1,14 +1,15 @@
source 'https://rubygems.org'
gem 'rails', '5.2.0.rc2'
gem 'sqlite3'
gem 'pg', '~> 0.21.0'
gem 'puma', '~> 3.11'
gem 'webpacker', '3.4.1'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'jbuilder', '~> 2.7'
gem 'oj', '~> 3.5.0'
gem 'kaminari', '~> 1.1.1'
gem 'unitwise', '~> 2.2.0'
gem 'redcarpet', '~> 3.4.0'
@ -19,6 +20,9 @@ gem 'tzinfo-data'
group :development, :test do
gem 'puma', '~> 3.11'
gem 'sqlite3'
gem 'guard', '~> 2.14.0'
gem 'guard-rspec', require: false
gem 'rspec-rails', '~> 3.7.2'

View File

@ -81,6 +81,18 @@ GEM
jbuilder (2.7.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
liner (0.2.4)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
@ -89,7 +101,7 @@ GEM
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.0.12)
lumberjack (1.0.13)
mail (2.7.0)
mini_mime (>= 0.1.1)
marcel (0.3.2)
@ -110,6 +122,7 @@ GEM
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
oj (3.5.0)
parslet (1.8.2)
pg (0.21.0)
pry (0.11.3)
@ -216,6 +229,8 @@ DEPENDENCIES
guard (~> 2.14.0)
guard-rspec
jbuilder (~> 2.7)
kaminari (~> 1.1.1)
oj (~> 3.5.0)
pg (~> 0.21.0)
puma (~> 3.11)
rails (= 5.2.0.rc2)

View File

@ -1,13 +1,34 @@
<template>
<div id="app">
<router-view></router-view>
<div>
<app-navbar></app-navbar>
<section id="app" class="section">
<div class="container">
<router-view v-if="!hasError"></router-view>
<div v-else>
<h1>Error!</h1>
<p>{{error}}</p>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
import { mapState } from "vuex";
import AppNavbar from "./AppNavbar";
export default {
computed: {
...mapState({
hasError: state => state.error !== null,
error: state => state.error
})
},
components: {
AppNavbar
}
}
</script>

View File

@ -0,0 +1,54 @@
<template>
<nav class="navbar is-primary" role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item" href="/">
PARSLEY
</a>
<div class="navbar-burger" :class="{ 'is-active': menuActive}" @click="menuActive = !menuActive">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="navbar-menu" :class="{ 'is-active': menuActive}">
<div class="navbar-start">
<router-link to="/" class="navbar-item">Recipes</router-link>
<router-link to="/ingredients" class="navbar-item">Ingredients</router-link>
<router-link to="/calculator" class="navbar-item">Calculator</router-link>
<router-link to="/about" class="navbar-item">About</router-link>
<router-link to="/notes" class="navbar-item">Notes</router-link>
<a class="navbar-item" href="/admin/users">Admin</a>
</div>
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable" >
<a class="navbar-link" href="#" @click.prevent>
Dan
</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="#">
Profile
</a>
<a class="navbar-item" href="#">
Logout
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
</template>
<script>
export default {
data() {
return {
menuActive: false
};
}
}
</script>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,14 @@
<template>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,13 +1,51 @@
<template>
<div>
list
<h1 class="title">Recipes</h1>
<button type="button" class="button">Create Recipe</button>
<table class="table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr v-for="r in recipes" :key="r.id">
<td>{{r.name}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
import api from "../lib/Api";
export default {
data() {
return {
recipeData: null
};
},
created() {
this.loadResource(api.getRecipeList(), data => this.recipeData = data);
},
computed: {
recipes() {
if (this.recipeData) {
return this.recipeData.recipes;
} else {
return [];
}
}
}
}
</script>

View File

@ -66,7 +66,18 @@ class Api {
return this.performRequest(url, "GET");
}
getRecipeList(page, per, sortColumn, sortDirection, name, tags) {
const params = {
page: page || null,
per: per || null,
sort_column: sortColumn || null,
sort_direction: sortDirection || null,
name: name || null,
tags: tags || null
};
return this.get("/recipes", params);
}
}
const api = new Api();

View File

@ -0,0 +1,26 @@
import Vue from 'vue';
import { mapMutations, mapState } from 'vuex';
Vue.mixin({
computed: {
...mapState({
isLoading: state => state.loading
})
},
methods: {
...mapMutations([
'setError',
'setLoading'
]),
loadResource(promise, successFunc) {
this.setLoading(true);
return promise
.then(successFunc)
.catch(err => this.setError(err))
.then(() => this.setLoading(false));
}
}
});

View File

@ -2,9 +2,9 @@ import '../styles';
import Vue from 'vue'
import config from '../config';
/// import 'App/lib/Fontawesome';
import store from '../store';
import router from '../router';
import '../lib/GlobalMixins';
import App from '../components/App';
//Vue.use(VueClipboard);

View File

@ -1,7 +1,13 @@
import Vue from 'vue';
import Router from 'vue-router';
import RecipeEdit from './components/RecipeEdit';
import RecipeShow from './components/RecipeShow';
import The404Page from './components/The404Page';
import TheAboutPage from './components/TheAboutPage';
import TheCalculator from './components/TheCalculator';
import TheIngredientList from './components/TheIngredientList';
import TheNotesList from './components/TheNotesList';
import TheRecipeList from './components/TheRecipeList';
Vue.use(Router);
@ -13,6 +19,36 @@ export default new Router({
name: 'recipeList',
component: TheRecipeList
},
{
path: '/recipes/:id/edit',
name: 'edit_recipe',
component: RecipeEdit
},
{
path: '/recipe/:id',
name: 'recipe',
component: RecipeShow
},
{
path: "/about",
name: "about",
component: TheAboutPage
},
{
path: "/calculator",
name: "calculator",
component: TheCalculator
},
{
path: "/ingredients",
name: "ingredients",
component: TheIngredientList
},
{
path: "/notes",
name: "notes",
component: TheNotesList
},
{
path: '*',
component: The404Page

View File

@ -6,13 +6,20 @@ Vue.use(Vuex);
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
state: {
loading: false,
error: null
},
getters: {
},
mutations: {
setLoading(state, value) {
state.loading = value;
},
setError(state, value) {
state.error = value;
}
},
actions: {

View File

@ -0,0 +1,10 @@
// Bluma default overrides
$green: #79A736;
$primary: $green;
// Make all Bulma variables and functions available
@import "~bulma/sass/utilities/initial-variables";
@import "~bulma/sass/utilities/functions";

View File

@ -0,0 +1,17 @@
@import "./variables";
@import "~bulma/sass/utilities/_all";
@import "~bulma/sass/base/_all";
@import "~bulma/sass/components/navbar";
@import "~bulma/sass/elements/_all";
@import "~bulma/sass/grid/columns";
@import "~bulma/sass/layout/section";
body {
background-color: $grey-dark;
}
#app .container {
padding: 1rem;
background-color: $background;
}

View File

@ -0,0 +1,10 @@
json.extract! @recipes, :total_count, :total_pages, :current_page
json.page_size @recipes.limit_value
json.recipes @recipes do |r|
json.extract! r, :id, :name, :rating, :yields, :total_time, :active_time, :created_at, :updated_at
json.tags r.tag_names
end

View File

@ -1,54 +1,88 @@
Rails.application.configure do
# Verifies that versions and hashed value of the package contents in the project's package.json
config.webpacker.check_yarn_integrity = false
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Code is not reloaded between requests.
config.cache_classes = true
# Do not eager load code on boot.
config.eager_load = false
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Show full error reports.
config.consider_all_requests_local = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = true
config.action_controller.perform_caching = true
# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp/caching-dev.txt').exist?
config.action_controller.perform_caching = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=172800'
}
else
config.action_controller.perform_caching = false
# # Compress JavaScripts and CSS.
# config.assets.js_compressor = :uglifier
# # config.assets.css_compressor = :sass
#
# # Do not fallback to assets pipeline if a precompiled asset is missed.
# config.assets.compile = false
config.cache_store = :null_store
end
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "parsley_#{Rails.env}"
config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# # Debug mode disables concatenation and preprocessing of assets.
# # This option may cause significant delays in view rendering with a large
# # number of complex assets.
# config.assets.debug = true
#
# # Suppress logger output for asset requests.
# config.assets.quiet = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
# config.file_watcher = ActiveSupport::EventedFileUpdateChecker
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end

View File

@ -1,4 +1,4 @@
version: '2'
version: '3'
services:
postgres:
@ -12,8 +12,6 @@ services:
build: .
ports:
- "3000:80"
volumes:
- .:/home/app/parsley/
links:
- postgres
volumes:

View File

@ -7,7 +7,7 @@ server {
passenger_ruby /usr/bin/ruby;
location ~ ^/(assets)/ {
location ~ ^/(assets|packs)/ {
gzip_static on;
expires max;
add_header Cache-Control public;

View File

@ -1,6 +1,7 @@
{
"dependencies": {
"@rails/webpacker": "^3.4.1",
"bulma": "^0.6.2",
"caniuse-lite": "^1.0.30000815",
"css-loader": "^0.28.11",
"vue": "^2.5.16",

View File

@ -1028,6 +1028,10 @@ builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
bulma@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.6.2.tgz#f4b1d11d5acc51a79644eb0a2b0b10649d3d71f5"
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -2626,7 +2630,7 @@ http-deceiver@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
http-errors@1.6.2, http-errors@~1.6.2:
http-errors@1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
dependencies:
@ -2635,6 +2639,15 @@ http-errors@1.6.2, http-errors@~1.6.2:
setprototypeof "1.0.3"
statuses ">= 1.3.1 < 2"
http-errors@~1.6.2:
version "1.6.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-parser-js@>=0.4.0:
version "0.4.11"
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.11.tgz#5b720849c650903c27e521633d94696ee95f3529"
@ -5361,7 +5374,7 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
"statuses@>= 1.3.1 < 2":
"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"