41 |
42 |
--------------------------------------------------------------------------------
/app/controllers/opinions_controller.rb:
--------------------------------------------------------------------------------
1 | class OpinionsController < ApplicationController
2 | before_action :user_signed_in, except: %i[index]
3 | before_action :ownership, only: %i[edit update]
4 |
5 | def ownership
6 | return unless current_user.owns?(params[:id])
7 |
8 | flash[:notice] = 'You do not own this post, you cannot edit nor delete it!'
9 | redirect_to root_path
10 | false
11 | end
12 |
13 | def index
14 | @opinions = if current_user.nil?
15 | Opinion.all.ordered_by_most_recent
16 | else
17 | current_user.opinion_feed.ordered_by_most_recent
18 | end
19 | @opinion = Opinion.new
20 | end
21 |
22 | def new
23 | @opinion = Opinion.new
24 | end
25 |
26 | def create
27 | opinion = current_user.opinions.build(opinion_params)
28 |
29 | if opinion.save
30 | flash[:notice] = 'Your book review about ' + opinion.book_name + ' was published'
31 | else
32 | flash[:errors] = opinion.errors.full_messages
33 | end
34 |
35 | redirect_to root_path
36 | end
37 |
38 | def show
39 | @opinion = Opinion.find(params[:id])
40 | @comments = Comment.all
41 | end
42 |
43 | def edit
44 | @opinion = Opinion.find(params[:id])
45 | @opinions = Opinion.all
46 | end
47 |
48 | def update
49 | opinion = Opinion.find(params[:id])
50 | if opinion.update(opinion_params)
51 | flash[:notice] = 'Your book review about ' + opinion.book_name + ' was updated'
52 | redirect_to opinion
53 | else
54 | flash[:errors] = opinion.errors.full_messages
55 | render :edit
56 | end
57 | end
58 |
59 | def destroy
60 | opinion = Opinion.find(params[:id])
61 | if opinion.destroy
62 | flash[:notice] = 'Your book review about ' + opinion.book_name + ' was deleted'
63 | else
64 | flash[:errors] = ['Could not delete this book review']
65 | end
66 | redirect_to root_path
67 | end
68 |
69 | private
70 |
71 | def opinion_params
72 | params.require(:opinion).permit(:book_name, :book_author, :published_at, :content, :book_link)
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/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 | config.action_view.cache_template_loading = true
11 |
12 | # Do not eager load code on boot. This avoids loading your whole application
13 | # just for the purpose of running a single test. If you are using a tool that
14 | # preloads Rails for running tests, you may have to set it to true.
15 | config.eager_load = false
16 |
17 | # Configure public file server for tests with Cache-Control for performance.
18 | config.public_file_server.enabled = true
19 | config.public_file_server.headers = {
20 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
21 | }
22 |
23 | # Show full error reports and disable caching.
24 | config.consider_all_requests_local = true
25 | config.action_controller.perform_caching = false
26 | config.cache_store = :null_store
27 |
28 | # Raise exceptions instead of rendering exception templates.
29 | config.action_dispatch.show_exceptions = false
30 |
31 | # Disable request forgery protection in test environment.
32 | config.action_controller.allow_forgery_protection = false
33 |
34 | # Store uploaded files on the local file system in a temporary directory.
35 | config.active_storage.service = :test
36 |
37 | config.action_mailer.perform_caching = false
38 |
39 | # Tell Action Mailer not to deliver emails to the real world.
40 | # The :test delivery method accumulates sent emails in the
41 | # ActionMailer::Base.deliveries array.
42 | config.action_mailer.delivery_method = :test
43 |
44 | # Print deprecation notices to the stderr.
45 | config.active_support.deprecation = :stderr
46 |
47 | # Raises error for missing translations.
48 | # config.action_view.raise_on_missing_translations = true
49 | end
50 |
--------------------------------------------------------------------------------
/spec/features/opinion_management_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | require 'capybara/rails'
3 |
4 | RSpec.describe 'Opinion management', type: :system do
5 | describe 'Manage opinions' do
6 | before(:each) do
7 | visit sign_up_path
8 | fill_in 'Fullname', with: 'Capybara Testor'
9 | fill_in 'Username', with: 'Capybara'
10 | page.attach_file('user_photo', Rails.root + 'app/assets/images/article-image3.jpg')
11 | page.attach_file('user_cover_image', Rails.root + 'app/assets/images/control-remedy.jpg')
12 | click_on 'Done'
13 | end
14 |
15 | it 'Access the create opinion form' do
16 | expect(page).to have_content('Book name')
17 | end
18 |
19 | it 'Create a new review, should redirect to root page if all is ok' do
20 | fill_in 'Book name', with: 'Capybara Testing Book'
21 | fill_in 'Book author', with: 'Capybara'
22 | fill_in 'Published at', with: DateTime.now
23 | fill_in 'opinion_content', with: 'It has been referred to as the greatest love story of
24 | all time, or perhaps the most tragic. Romeo and Juliet serves to satisfy both anyway,
25 | which for a 1595 play has obviously stuck around for a very long time, which points to how
26 | good a book can turn out to be centuries after its author graced our good planet.'
27 | click_on 'Done'
28 | expect(page).to have_content('Capybara Testing Book')
29 | end
30 |
31 | it 'Show a review, should redirect to review page' do
32 | fill_in 'Book name', with: 'Capybara Testing Book'
33 | fill_in 'Book author', with: 'Capybara'
34 | fill_in 'Published at', with: DateTime.now
35 | fill_in 'opinion_content', with: 'It has been referred to as the greatest love
36 | story of all time, or perhaps the most tragic. Romeo and Juliet serves to satisfy both anyway,
37 | which for a 1595 play has obviously stuck around for a very long time, which points to how
38 | good a book can turn out to be centuries after its author graced our good planet.'
39 | click_on 'Done'
40 |
41 | expect(page).to have_content('Capybara Testing Book')
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/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.3', '>= 6.0.3.1'
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', '~> 4.1'
12 |
13 | gem 'bootstrap', '~> 4.5'
14 | # Use SCSS for stylesheets
15 | gem 'sass-rails', '>= 6'
16 | # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
17 | gem 'webpacker', '~> 4.0'
18 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
19 | gem 'turbolinks', '~> 5'
20 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
21 | gem 'jbuilder', '~> 2.7'
22 | # Use Redis adapter to run Action Cable in production
23 | # gem 'redis', '~> 4.0'
24 | # Use Active Model has_secure_password
25 | # gem 'bcrypt', '~> 3.1.7'
26 |
27 | # Use Active Storage variant
28 | gem 'image_processing', '~> 1.2'
29 |
30 | # Reduces boot times through caching; required in config/boot.rb
31 | gem 'bootsnap', '>= 1.4.2', require: false
32 |
33 | gem 'cloudinary'
34 |
35 | group :development, :test do
36 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
37 | gem 'byebug', platforms: %i[mri mingw x64_mingw]
38 | end
39 |
40 | group :development do
41 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
42 | gem 'listen', '~> 3.2'
43 | gem 'web-console', '>= 3.3.0'
44 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
45 | gem 'rubocop'
46 | gem 'spring'
47 | gem 'spring-watcher-listen', '~> 2.0.0'
48 | end
49 |
50 | group :test do
51 | # Adds support for Capybara system testing and selenium driver
52 | gem 'capybara', '>= 2.15'
53 | gem 'selenium-webdriver'
54 | # Easy installation and use of web drivers to run system tests with browsers
55 | gem 'rspec-rails'
56 | gem 'shoulda-matchers'
57 | gem 'webdrivers'
58 | end
59 |
60 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
61 | gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
62 |
--------------------------------------------------------------------------------
/app/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 |
61 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 9.1 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On OS X with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On OS X 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 | # http://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
23 |
24 |
25 | development:
26 | <<: *default
27 | database: book_review_development
28 |
29 | # The specified database role being used to connect to postgres.
30 | # To create additional roles in postgres see `$ createuser --help`.
31 | # When left blank, postgres will use the default role. This is
32 | # the same name as the operating system user that initialized the database.
33 | #username: ror_social_scaffold
34 |
35 | # The password associated with the postgres role (username).
36 | #password:
37 |
38 | # Connect on a TCP socket. Omitted by default since the client uses a
39 | # domain socket that doesn't need configuration. Windows does not have
40 | # domain sockets, so uncomment these lines.
41 | #host: localhost
42 |
43 | # The TCP port the server listens on. Defaults to 5432.
44 | # If your server runs on a different port number, change accordingly.
45 | #port: 5432
46 |
47 | # Schema search path. The server defaults to $user,public
48 | #schema_search_path: myapp,sharedapp,public
49 |
50 | # Minimum log levels, in increasing order:
51 | # debug5, debug4, debug3, debug2, debug1,
52 | # log, notice, warning, error, fatal, and panic
53 | # Defaults to warning.
54 | #min_messages: notice
55 |
56 | # Warning: The database defined as "test" will be erased and
57 | # re-generated from your development database when you run "rake".
58 | # Do not set this db to the same as development or production.
59 | test:
60 | <<: *default
61 | database: book_review_test
62 |
63 | # As with config/secrets.yml, you never want to store sensitive information,
64 | # like your database password, in your source code. If your source code is
65 | # ever seen by anyone, they now have access to your database.
66 | #
67 | # Instead, provide the password as a unix environment variable when you boot
68 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
69 | # for a full rundown on how to provide these environment variables in a
70 | # production deployment.
71 | #
72 | # On Heroku and other platform providers, you may have a full connection URL
73 | # available as an environment variable. For example:
74 | #
75 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
76 | #
77 | # You can use this database configuration with:
78 | #
79 | # production:
80 | # url: <%= ENV['DATABASE_URL'] %>
81 | #
82 | production:
83 | <<: *default
84 | database: book_review_production
85 | username: rails_template
86 | password: <%= ENV['BOOK_REVIEW_DATABASE_PASSWORD'] %>
87 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | require 'spec_helper'
3 | ENV['RAILS_ENV'] ||= 'test'
4 | require File.expand_path('../config/environment', __dir__)
5 | # Prevent database truncation if the environment is production
6 | abort('The Rails environment is running in production mode!') if Rails.env.production?
7 | require 'rspec/rails'
8 | # Add additional requires below this line. Rails is not loaded until this point!
9 | require 'shoulda/matchers'
10 | # Requires supporting ruby files with custom matchers and macros, etc, in
11 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
12 | # run as spec files by default. This means that files in spec/support that end
13 | # in _spec.rb will both be required and run as specs, causing the specs to be
14 | # run twice. It is recommended that you do not name files matching this glob to
15 | # end with _spec.rb. You can configure this pattern with the --pattern
16 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
17 | #
18 | # The following line is provided for convenience purposes. It has the downside
19 | # of increasing the boot-up time by auto-requiring all files in the support
20 | # directory. Alternatively, in the individual `*_spec.rb` files, manually
21 | # require only the support files necessary.
22 | #
23 | # Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
24 |
25 | # Checks for pending migrations and applies them before tests are run.
26 | # If you are not using ActiveRecord, you can remove these lines.
27 | begin
28 | ActiveRecord::Migration.maintain_test_schema!
29 | rescue ActiveRecord::PendingMigrationError => e
30 | puts e.to_s.strip
31 | exit 1
32 | end
33 | RSpec.configure do |config|
34 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
35 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
36 |
37 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
38 | # examples within a transaction, remove the following line or assign false
39 | # instead of true.
40 | config.use_transactional_fixtures = true
41 |
42 | # You can uncomment this line to turn off ActiveRecord support entirely.
43 | # config.use_active_record = false
44 |
45 | # RSpec Rails can automatically mix in different behaviours to your tests
46 | # based on their file location, for example enabling you to call `get` and
47 | # `post` in specs under `spec/controllers`.
48 | #
49 | # You can disable this behaviour by removing the line below, and instead
50 | # explicitly tag your specs with their type, e.g.:
51 | #
52 | # RSpec.describe UsersController, type: :controller do
53 | # # ...
54 | # end
55 | #
56 | # The different available types are documented in the features, such as in
57 | # https://relishapp.com/rspec/rspec-rails/docs
58 | config.infer_spec_type_from_file_location!
59 |
60 | # Filter lines from Rails gems in backtraces.
61 | config.filter_rails_from_backtrace!
62 | # arbitrary gems may also be filtered via:
63 | # config.filter_gems_from_backtrace("gem name")
64 | end
65 | Shoulda::Matchers.configure do |config|
66 | config.integrate do |with|
67 | with.test_framework :rspec
68 | with.library :rails
69 | end
70 | end
71 | Capybara.default_driver = :selenium_chrome
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Book review social media
3 |
4 | > This is a social media web app for book lovers. It is always good to interact with people who share the same hobbies with you. Most important it is better to have some reviews about things before buying or viewing them, especially for book. 'Book Review' aims to connect books lovers and help them share their experiences about the books they have read before.
5 |
6 | 
7 |
8 | > The actions the any user could do in the app are
9 | - preview all book reviews and trending ones
10 | - Register
11 | - Sign in
12 | - Post a book review
13 | - Follow some interesting book reviewers
14 | - Like/dislike a book review
15 | - Comment a book review
16 |
17 | > Thechnically speaking, the database schema is quite simple, made up with Lucidchart and goes like this: (You can get the file [here](https://github.com/patriciachrysy/rails-capstone-project/tree/feature/docs) )
18 |
19 | 
20 |
21 |
22 | > Wana know more? Watch the presentation video.
23 |
24 | [](https://www.loom.com/share/8af38510db29488c93d7366e89c5fa05)
25 |
26 | ## Built With
27 |
28 | > The project was built using these technologies
29 | - Ruby v2.7.0
30 | - Ruby on Rails v6.0.3
31 |
32 | ## Live Demo
33 |
34 |
35 | > Try out the app here: [book_review](https://powerful-wildwood-46604.herokuapp.com/)
36 |
37 |
38 | ## Getting Started
39 |
40 | To get a local copy up and running follow these simple example steps.
41 |
42 | - Clone the repository and there you go! ;-)
43 |
44 | ### Prerequisites
45 |
46 | Ruby: 2.7
47 | Rails: 6.0.3
48 | Postgres: >=9.5
49 |
50 | ### Setup
51 |
52 | - cd into the folder
53 | - install the the bundles with the `bundle` or `bundle install` command. If you are asked to do `bundle update` before, do it.
54 | - Set up the database using `rake db:migrate` or `rails db:migrate`
55 |
56 | ### Install
57 |
58 | - Install VSCode or any code editor you like
59 | - Install Ruby on rails 5.1.6 or later if you don't have it yet
60 | - Run this command on your terminal in order to install rubocop: gem install rubocop
61 |
62 |
63 |
64 |
65 | ### Usage
66 |
67 | Start server with:
68 |
69 | ```
70 | rails server
71 | ```
72 |
73 | Open `http://localhost:3000/` in your browser.
74 |
75 | ### Run tests
76 |
77 | ```
78 | rpsec --format documentation
79 | ```
80 |
81 | ### Deployment
82 |
83 | > Follow the [Heroku deployment doc](https://devcenter.heroku.com/articles/getting-started-with-rails5) to deploy th app on heroku
84 |
85 | ## Special Credit
86 |
87 | > Original site design by Gregoire Vella on Behance [Check it!](https://www.behance.net/gallery/14286087/Twitter-Redesign-of-UI-details)
88 |
89 | ## Authors
90 |
91 |
92 | 👤 **Manezeu Patricia Chrystelle**
93 | - Github: [@githubhandle](https://github.com/patriciachrysy)
94 | - Twitter: [@twitterhandle](https://twitter.com/ManezeuP)
95 | - Linkedin: [linkedin](https://www.linkedin.com/in/manezeu-patricia-chrystelle-095072118/)
96 |
97 |
98 | ## 🤝 Contributing
99 |
100 | Contributions, issues and feature requests are welcome!
101 |
102 | Feel free to check the [issues page](https://github.com/patriciachrysy/rails-capstone-project/issues).
103 |
104 | ## Show your support
105 |
106 | Give a ⭐️ if you like this project!
107 |
108 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
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 | @import 'bootstrap';
17 |
18 | body {
19 | font-family: 'Lato', sans-serif;
20 | }
21 |
22 | a {
23 | text-decoration: none;
24 | }
25 |
26 | a:hover {
27 | text-decoration: none;
28 | font-size: 20px;
29 | color: #53a7e7;
30 | }
31 |
32 | ul {
33 | list-style: none;
34 | padding: 0 !important;
35 | margin: 0 !important;
36 | width: 100%;
37 | }
38 |
39 | li i {
40 | font-size: 25px !important;
41 | }
42 |
43 | li:hover {
44 | background-color: #53a7e7;
45 | color: white !important;
46 | }
47 |
48 | li a:hover {
49 | font-size: 1rem;
50 | color: white !important;
51 | }
52 |
53 | .blue {
54 | color: #53a7e7;
55 | }
56 |
57 | .bg-blue {
58 | background-color: #53a7e7;
59 | }
60 |
61 | .ice-blue {
62 | color: #396f9b;
63 | }
64 |
65 | .dark-blue {
66 | color: #213246;
67 | }
68 |
69 | .bg-dark-blue {
70 | background-color: #213246;
71 | }
72 |
73 | .dark-grey {
74 | color: #6e8597;
75 | }
76 |
77 | .grey {
78 | color: #bebfc1;
79 | }
80 |
81 | .bg-ligth-grey {
82 | background-color: #f5f6f8;
83 | }
84 |
85 | .black-border {
86 | border: 1px solid #16272f;
87 | }
88 |
89 | .icy-blue {
90 | color: #b4c5cd;
91 | }
92 |
93 | .medium-text {
94 | font-size: 15px;
95 | }
96 |
97 | .big-text {
98 | font-size: 25px !important;
99 | }
100 |
101 | .profile-pic {
102 | width: 100px;
103 | height: 100px;
104 | border-radius: 5px;
105 | }
106 |
107 | .small-profile-pic {
108 | width: 60px;
109 | height: 60px;
110 | border-radius: 5px;
111 | }
112 |
113 | .text-extra-medium {
114 | font-size: 17px;
115 | }
116 |
117 | .logo {
118 | width: 50px;
119 | height: 50px;
120 | }
121 |
122 | .logo-text {
123 | font-family: 'Fredericka the Great', cursive;
124 | font-size: 35px;
125 | color: white;
126 | }
127 |
128 | .logo-text:hover {
129 | text-decoration: none;
130 | font-size: 35px !important;
131 | color: white !important;
132 | }
133 |
134 | .login-button:hover {
135 | text-decoration: none;
136 | font-size: 1rem !important;
137 | color: white !important;
138 | }
139 |
140 | .align-self-center {
141 | overflow-x: hidden;
142 | }
143 |
144 | .grey-border-bottom {
145 | border-bottom: 2px solid #e3e4e6;
146 | }
147 |
148 | .grey-border-right {
149 | border-right: 2px solid #e3e4e6;
150 | }
151 |
152 | .grey-border {
153 | border: 2px solid #e3e4e6;
154 | }
155 |
156 | .small-text {
157 | font-size: 13px;
158 | }
159 |
160 | .user-pic {
161 | width: 50px;
162 | height: 50px;
163 | border-radius: 50%;
164 | }
165 |
166 | .cover-image {
167 | width: 100%;
168 | height: 350px;
169 | }
170 |
171 | .full-width {
172 | width: 100%;
173 | }
174 |
--------------------------------------------------------------------------------
/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
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 ||=
65 | env_var_version || cli_arg_version ||
66 | lockfile_version
67 | end
68 |
69 | def bundler_requirement
70 | return "#{Gem::Requirement.default}.a" unless bundler_version
71 |
72 | bundler_gem_version = Gem::Version.new(bundler_version)
73 |
74 | requirement = bundler_gem_version.approximate_recommendation
75 |
76 | return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
77 |
78 | requirement += ".a" if bundler_gem_version.prerelease?
79 |
80 | requirement
81 | end
82 |
83 | def load_bundler!
84 | ENV["BUNDLE_GEMFILE"] ||= gemfile
85 |
86 | activate_bundler
87 | end
88 |
89 | def activate_bundler
90 | gem_error = activation_error_handling do
91 | gem "bundler", bundler_requirement
92 | end
93 | return if gem_error.nil?
94 | require_error = activation_error_handling do
95 | require "bundler/version"
96 | end
97 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
98 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
99 | exit 42
100 | end
101 |
102 | def activation_error_handling
103 | yield
104 | nil
105 | rescue StandardError, LoadError => e
106 | e
107 | end
108 | end
109 |
110 | m.load_bundler!
111 |
112 | if m.invoked_as_script?
113 | load Gem.bin_path("bundler", "bundle")
114 | end
115 |
--------------------------------------------------------------------------------
/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: 2020_06_09_125526) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "active_storage_attachments", force: :cascade do |t|
19 | t.string "name", null: false
20 | t.string "record_type", null: false
21 | t.bigint "record_id", null: false
22 | t.bigint "blob_id", null: false
23 | t.datetime "created_at", null: false
24 | t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
25 | t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
26 | end
27 |
28 | create_table "active_storage_blobs", force: :cascade do |t|
29 | t.string "key", null: false
30 | t.string "filename", null: false
31 | t.string "content_type"
32 | t.text "metadata"
33 | t.bigint "byte_size", null: false
34 | t.string "checksum", null: false
35 | t.datetime "created_at", null: false
36 | t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
37 | end
38 |
39 | create_table "comments", force: :cascade do |t|
40 | t.text "content"
41 | t.datetime "created_at", precision: 6, null: false
42 | t.datetime "updated_at", precision: 6, null: false
43 | t.integer "author_id"
44 | t.integer "opinion_id"
45 | t.index ["author_id"], name: "index_comments_on_author_id"
46 | t.index ["opinion_id"], name: "index_comments_on_opinion_id"
47 | end
48 |
49 | create_table "followings", force: :cascade do |t|
50 | t.datetime "created_at", precision: 6, null: false
51 | t.datetime "updated_at", precision: 6, null: false
52 | t.integer "follower_id"
53 | t.integer "followed_id"
54 | t.index ["followed_id"], name: "index_followings_on_followed_id"
55 | t.index ["follower_id"], name: "index_followings_on_follower_id"
56 | end
57 |
58 | create_table "likings", force: :cascade do |t|
59 | t.boolean "status"
60 | t.datetime "created_at", precision: 6, null: false
61 | t.datetime "updated_at", precision: 6, null: false
62 | t.integer "user_id"
63 | t.integer "opinion_id"
64 | t.index ["opinion_id"], name: "index_likings_on_opinion_id"
65 | t.index ["user_id"], name: "index_likings_on_user_id"
66 | end
67 |
68 | create_table "opinions", force: :cascade do |t|
69 | t.string "book_name"
70 | t.string "book_author"
71 | t.date "published_at"
72 | t.string "book_link"
73 | t.text "content"
74 | t.datetime "created_at", precision: 6, null: false
75 | t.datetime "updated_at", precision: 6, null: false
76 | t.integer "author_id"
77 | t.index ["author_id"], name: "index_opinions_on_author_id"
78 | end
79 |
80 | create_table "users", force: :cascade do |t|
81 | t.string "username"
82 | t.string "fullname"
83 | t.datetime "created_at", precision: 6, null: false
84 | t.datetime "updated_at", precision: 6, null: false
85 | end
86 |
87 | add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
88 | end
89 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 |
89 | <% @user.followers.each do |user| %>
90 | <%= render user %>
91 | <% end %>
92 |
93 |
94 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause
4 | # this file to always be loaded, without a need to explicitly require it in any
5 | # files.
6 | #
7 | # Given that it is always loaded, you are encouraged to keep this file as
8 | # light-weight as possible. Requiring heavyweight dependencies from this file
9 | # will add to the boot time of your test suite on EVERY test run, even for an
10 | # individual file that may not need all of that loaded. Instead, consider making
11 | # a separate helper file that requires the additional dependencies and performs
12 | # the additional setup, and require it from the spec files that actually need
13 | # it.
14 | #
15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16 | RSpec.configure do |config|
17 | # rspec-expectations config goes here. You can use an alternate
18 | # assertion/expectation library such as wrong or the stdlib/minitest
19 | # assertions if you prefer.
20 | config.expect_with :rspec do |expectations|
21 | # This option will default to `true` in RSpec 4. It makes the `description`
22 | # and `failure_message` of custom matchers include text for helper methods
23 | # defined using `chain`, e.g.:
24 | # be_bigger_than(2).and_smaller_than(4).description
25 | # # => "be bigger than 2 and smaller than 4"
26 | # ...rather than:
27 | # # => "be bigger than 2"
28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29 | end
30 |
31 | # rspec-mocks config goes here. You can use an alternate test double
32 | # library (such as bogus or mocha) by changing the `mock_with` option here.
33 | config.mock_with :rspec do |mocks|
34 | # Prevents you from mocking or stubbing a method that does not exist on
35 | # a real object. This is generally recommended, and will default to
36 | # `true` in RSpec 4.
37 | mocks.verify_partial_doubles = true
38 | end
39 |
40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41 | # have no way to turn it off -- the option exists only for backwards
42 | # compatibility in RSpec 3). It causes shared context metadata to be
43 | # inherited by the metadata hash of host groups and examples, rather than
44 | # triggering implicit auto-inclusion in groups with matching metadata.
45 | config.shared_context_metadata_behavior = :apply_to_host_groups
46 |
47 | # The settings below are suggested to provide a good initial experience
48 | # with RSpec, but feel free to customize to your heart's content.
49 | # # This allows you to limit a spec run to individual examples or groups
50 | # # you care about by tagging them with `:focus` metadata. When nothing
51 | # # is tagged with `:focus`, all examples get run. RSpec also provides
52 | # # aliases for `it`, `describe`, and `context` that include `:focus`
53 | # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
54 | # config.filter_run_when_matching :focus
55 | #
56 | # # Allows RSpec to persist some state between runs in order to support
57 | # # the `--only-failures` and `--next-failure` CLI options. We recommend
58 | # # you configure your source control system to ignore this file.
59 | # config.example_status_persistence_file_path = "spec/examples.txt"
60 | #
61 | # # Limits the available syntax to the non-monkey patched syntax that is
62 | # # recommended. For more details, see:
63 | # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
64 | # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
65 | # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
66 | # config.disable_monkey_patching!
67 | #
68 | # # Many RSpec users commonly either run the entire suite or an individual
69 | # # file, and it's useful to allow more verbose output when running an
70 | # # individual spec file.
71 | # if config.files_to_run.one?
72 | # # Use the documentation formatter for detailed output,
73 | # # unless a formatter has already been configured
74 | # # (e.g. via a command-line flag).
75 | # config.default_formatter = "doc"
76 | # end
77 | #
78 | # # Print the 10 slowest examples and example groups at the
79 | # # end of the spec run, to help surface which specs are running
80 | # # particularly slow.
81 | # config.profile_examples = 10
82 | #
83 | # # Run specs in random order to surface order dependencies. If you find an
84 | # # order dependency and want to debug it, you can fix the order by providing
85 | # # the seed, which is printed after each run.
86 | # # --seed 1234
87 | # config.order = :random
88 | #
89 | # # Seed global randomization in this process using the `--seed` CLI option.
90 | # # Setting this allows you to use `--seed` to deterministically reproduce
91 | # # test failures related to randomization by passing the same `--seed` value
92 | # # as the one that triggered the failure.
93 | # Kernel.srand config.seed
94 | end
95 |
--------------------------------------------------------------------------------
/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 = :cloudinary
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 = "rails_template_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 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Book Review
5 | <%= csrf_meta_tags %>
6 | <%= csp_meta_tag %>
7 |
8 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
9 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |