Skip to content

Commit

Permalink
Merge pull request #6 from metacorn/Part_7_ActiveStorage
Browse files Browse the repository at this point in the history
Part 7. ActiveStorage.
  • Loading branch information
metacorn authored Jun 30, 2019
2 parents 5d7f39c + 5f516dd commit c305ff6
Show file tree
Hide file tree
Showing 44 changed files with 496 additions and 86 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@

# Ignore database settings
/config/database.yml

# Ignore secret configs
/config/secrets/*
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ gem 'uglifier', '>= 1.3.0'
gem 'devise'
# JS
gem 'jquery-rails'
# UI
gem 'bootstrap', '~> 4.3.1'
# Google Cloud Storage
gem "google-cloud-storage", "~> 1.11", require: false

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
Expand Down
81 changes: 75 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,19 @@ GEM
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
arel (9.0.0)
autoprefixer-rails (9.6.0)
execjs
bcrypt (3.1.13)
bindex (0.7.0)
bootsnap (1.4.4)
msgpack (~> 1.0)
bootstrap (4.3.1)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.14.3, < 2)
sassc-rails (>= 2.0.0)
builder (3.2.3)
byebug (11.0.1)
capybara (3.24.0)
capybara (3.25.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
Expand All @@ -70,23 +76,55 @@ GEM
coffee-script-source (1.12.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
declarative (0.0.10)
declarative-option (0.1.0)
devise (4.6.2)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0)
responders
warden (~> 1.2.3)
diff-lcs (1.3)
digest-crc (0.4.1)
erubi (1.8.0)
execjs (2.7.0)
factory_bot (5.0.2)
activesupport (>= 4.2.0)
factory_bot_rails (5.0.2)
factory_bot (~> 5.0.2)
railties (>= 4.2.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
ffi (1.11.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
google-api-client (0.30.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.5, < 0.10.0)
httpclient (>= 2.8.1, < 3.0)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.10)
google-cloud-core (1.3.0)
google-cloud-env (~> 1.0)
google-cloud-env (1.2.0)
faraday (~> 0.11)
google-cloud-storage (1.18.2)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.26)
google-cloud-core (~> 1.2)
googleauth (>= 0.6.2, < 0.10.0)
mime-types (~> 3.0)
googleauth (0.8.1)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
httpclient (2.8.3)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jbuilder (2.9.1)
Expand All @@ -95,6 +133,7 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jwt (2.2.1)
launchy (2.4.3)
addressable (~> 2.3)
listen (3.1.5)
Expand All @@ -108,18 +147,26 @@ GEM
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
memoist (0.16.0)
method_source (0.9.2)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331)
mimemagic (0.3.3)
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
msgpack (1.3.0)
multi_json (1.13.1)
multipart-post (2.1.1)
nio4r (2.3.1)
nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
orm_adapter (0.5.0)
os (1.0.1)
pg (1.1.4)
public_suffix (3.1.0)
popper_js (1.14.5)
public_suffix (3.1.1)
puma (3.12.1)
rack (2.0.7)
rack-test (1.1.0)
Expand Down Expand Up @@ -157,10 +204,15 @@ GEM
rb-inotify (0.10.0)
ffi (~> 1.0)
regexp_parser (1.5.1)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
railties (>= 4.2.0, < 6.0)
rspec-core (3.8.1)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
responders (3.0.0)
actionpack (>= 5.0)
railties (>= 5.0)
retriable (3.1.2)
rspec-core (3.8.2)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0)
Expand Down Expand Up @@ -190,11 +242,25 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sassc (2.0.1)
ffi (~> 1.9)
rake
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
selenium-webdriver (3.142.3)
childprocess (>= 0.5, < 2.0)
rubyzip (~> 1.2, >= 1.2.2)
shoulda-matchers (4.1.0)
activesupport (>= 4.2.0)
signet (0.11.0)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
slim (4.0.1)
temple (>= 0.7.6, < 0.9)
tilt (>= 2.0.6, < 2.1)
Expand Down Expand Up @@ -222,6 +288,7 @@ GEM
turbolinks-source (5.2.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uber (0.1.0)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
warden (1.2.8)
Expand All @@ -246,11 +313,13 @@ PLATFORMS

DEPENDENCIES
bootsnap (>= 1.1.0)
bootstrap (~> 4.3.1)
byebug
capybara (>= 2.15)
coffee-rails (~> 4.2)
devise
factory_bot_rails
google-cloud-storage (~> 1.11)
jbuilder (~> 2.5)
jquery-rails
launchy
Expand Down
3 changes: 3 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
//= require activestorage
//= require turbolinks
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require activestorage
//= require_tree .
3 changes: 3 additions & 0 deletions app/assets/javascripts/files.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
2 changes: 1 addition & 1 deletion app/assets/javascripts/questions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
$(document).on('turbolinks:load', function() {
$('.edit-question-link').on('click', function(e) {
$('.question').on('click', '.edit-question-link', function(e) {
e.preventDefault()
$(this).hide()
var questionId = $(this).data('questionId')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
*= require_tree .
*= require_self
*/

// Custom bootstrap variables must be set or imported *before* bootstrap.
@import "bootstrap";
3 changes: 3 additions & 0 deletions app/assets/stylesheets/files.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the Files controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
2 changes: 1 addition & 1 deletion app/controllers/answers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def mark
private

def answer_params
params.require(:answer).permit(:body)
params.require(:answer).permit(:body, files: [])
end

def set_answer
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/files_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class FilesController < ApplicationController
def destroy
@file = ActiveStorage::Attachment.find(params[:id])
return head :forbidden unless @file.record_type.in?(%w[Question Answer])
@file.purge if current_user&.owner?(@file.record)
end
end
4 changes: 2 additions & 2 deletions app/controllers/questions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ def destroy
private

def set_question
@question = Question.find(params[:id])
@question = Question.with_attached_files.find(params[:id])
end

def question_params
params.require(:question).permit(:title, :body)
params.require(:question).permit(:title, :body, files: [])
end
end
2 changes: 2 additions & 0 deletions app/helpers/files_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module FilesHelper
end
2 changes: 2 additions & 0 deletions app/models/answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ class Answer < ApplicationRecord
belongs_to :user
belongs_to :question

has_many_attached :files

default_scope { order(best: :desc, created_at: :asc) }
scope :best, -> { where(best: true) }

Expand Down
4 changes: 4 additions & 0 deletions app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ class Question < ApplicationRecord
belongs_to :user
has_many :answers, dependent: :destroy

has_many_attached :files

default_scope { order(:created_at) }

validates :title, presence: true,
length: { in: 15..75 },
uniqueness: { case_sensitive: false }
Expand Down
26 changes: 19 additions & 7 deletions app/views/answers/_answer.html.slim
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
div id="answer_#{answer.id}"
div id="answer_#{answer.id}" class="mb-3"
- if answer.persisted?

- if answer.best?
div id="best-answer"
h4 The best answer
p= answer.body
p= render(partial: 'shared/answer_links', locals: { answer: answer })
h5 The best answer

p class="mb-1"= answer.body

- if answer.files.attached?
div class="answer-files mb-1"
- answer.files.each do |file|
p.mb-0
= link_to file.filename.to_s, url_for(file)
=< link_to('Delete file', file_path(file), method: :delete, remote: true) if current_user&.owner?(answer)

p class="mb-1"= render(partial: 'shared/answer_links', locals: { answer: answer })

= form_with model: answer, class: 'hidden', html: { id: "edit-answer-#{answer.id}" } do |f|
= f.label :body, 'Your answer'
= f.text_area :body
= f.submit 'Update'
div= f.label :body, 'Your answer', class: "mb-0"
div= f.text_area :body, cols: 32, rows: 3
div= f.label :files, 'Files', class: "mb-0"
div= f.file_field :files, multiple: true, direct_upload: true, class: "mb-3"
div= f.submit 'Update'
7 changes: 7 additions & 0 deletions app/views/files/destroy.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<% if @file.record_type == "Question" %>
<% @question = @file.record %>
$("#question_" + <%= @question.id %>).replaceWith('<%= j render 'questions/question_for_show', resource: @question %>')
<% elsif @file.record_type == "Answer" %>
<% @answer = @file.record %>
$("#answer_" + <%= @answer.id %>).replaceWith('<%= j render 'answers/answer', answer: @answer %>')
<% end %>
18 changes: 0 additions & 18 deletions app/views/layouts/application.html.erb

This file was deleted.

19 changes: 19 additions & 0 deletions app/views/layouts/application.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
doctype html
html
head
title QnA
= csrf_meta_tags
= csp_meta_tag
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
body
div class="navbar navbar-expand-sm navbar-light bg-light"
= render 'shared/user_nav'
div class="container"
div class="mt-2 row justify-content-center"
div class="col col-sm-6"
- if flash[:notice].present?
p.notice= notice
- if flash[:alert].present?
p.alert= alert
= yield
3 changes: 2 additions & 1 deletion app/views/questions/_question.html.slim
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
p= question.title
p
= link_to question.title, question_path(question)
Loading

0 comments on commit c305ff6

Please sign in to comment.