├── .gitignore
├── .rspec
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── Guardfile
├── LICENSE.md
├── Procfile
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ ├── .keep
│ │ ├── kitten.jpg
│ │ └── rails.png
│ ├── javascripts
│ │ ├── account_activations.coffee
│ │ ├── application.js
│ │ ├── cable.js
│ │ ├── channels
│ │ │ └── .keep
│ │ ├── microposts.coffee
│ │ ├── password_resets.coffee
│ │ ├── relationships.coffee
│ │ ├── sessions.coffee
│ │ ├── static_pages.coffee
│ │ └── users.coffee
│ └── stylesheets
│ │ ├── account_activations.scss
│ │ ├── application.css
│ │ ├── custom.scss
│ │ ├── microposts.scss
│ │ ├── password_resets.scss
│ │ ├── relationships.scss
│ │ ├── sessions.scss
│ │ ├── static_pages.scss
│ │ └── users.scss
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── account_activations_controller.rb
│ ├── api
│ │ └── v1
│ │ │ ├── base_controller.rb
│ │ │ ├── feeds_controller.rb
│ │ │ ├── followers_controller.rb
│ │ │ ├── followings_controller.rb
│ │ │ ├── microposts_controller.rb
│ │ │ ├── root_controller.rb
│ │ │ ├── sessions_controller.rb
│ │ │ └── users_controller.rb
│ ├── application_controller.rb
│ ├── concerns
│ │ ├── .keep
│ │ └── custom_errors.rb
│ ├── microposts_controller.rb
│ ├── password_resets_controller.rb
│ ├── relationships_controller.rb
│ ├── sessions_controller.rb
│ ├── static_pages_controller.rb
│ └── users_controller.rb
├── helpers
│ ├── account_activations_helper.rb
│ ├── application_helper.rb
│ ├── microposts_helper.rb
│ ├── password_resets_helper.rb
│ ├── relationships_helper.rb
│ ├── sessions_helper.rb
│ ├── static_pages_helper.rb
│ └── users_helper.rb
├── jobs
│ └── application_job.rb
├── mailers
│ ├── application_mailer.rb
│ └── user_mailer.rb
├── models
│ ├── application_record.rb
│ ├── concerns
│ │ └── .keep
│ ├── micropost.rb
│ ├── relationship.rb
│ └── user.rb
├── policies
│ ├── application_policy.rb
│ ├── follower_policy.rb
│ ├── following_policy.rb
│ ├── micropost_policy.rb
│ └── user_policy.rb
├── serializers
│ └── api
│ │ └── v1
│ │ ├── base_serializer.rb
│ │ ├── error_serializer.rb
│ │ ├── micropost_serializer.rb
│ │ ├── session_serializer.rb
│ │ └── user_serializer.rb
├── uploaders
│ └── picture_uploader.rb
└── views
│ ├── layouts
│ ├── _footer.html.erb
│ ├── _header.html.erb
│ ├── _shim.html.erb
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ ├── microposts
│ └── _micropost.html.erb
│ ├── password_resets
│ ├── edit.html.erb
│ └── new.html.erb
│ ├── relationships
│ ├── create.js.erb
│ └── destroy.js.erb
│ ├── sessions
│ └── new.html.erb
│ ├── shared
│ ├── _error_messages.html.erb
│ ├── _feed.html.erb
│ ├── _micropost_form.html.erb
│ ├── _stats.html.erb
│ └── _user_info.html.erb
│ ├── static_pages
│ ├── about.html.erb
│ ├── contact.html.erb
│ ├── help.html.erb
│ └── home.html.erb
│ ├── user_mailer
│ ├── account_activation.html.erb
│ ├── account_activation.text.erb
│ ├── ember_account_activation.html.erb
│ ├── ember_account_activation.text.erb
│ ├── password_reset.html.erb
│ └── password_reset.text.erb
│ └── users
│ ├── _follow.html.erb
│ ├── _follow_form.html.erb
│ ├── _unfollow.html.erb
│ ├── _user.html.erb
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── new.html.erb
│ ├── show.html.erb
│ └── show_follow.html.erb
├── bin
├── bundle
├── rails
├── rake
├── setup
└── update
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── active_model_serializers.rb
│ ├── active_record_belongs_to_required_by_default.rb
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── callback_terminator.rb
│ ├── carrier_wave.rb
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ ├── per_form_csrf_tokens.rb
│ ├── rack_attack.rb
│ ├── request_forgery_protection.rb
│ ├── session_store.rb
│ ├── ssl_options.rb
│ ├── to_time_preserves_timezone.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── puma.rb
├── routes.rb
├── secrets.yml
└── spring.rb
├── db
├── migrate
│ ├── 20160523185459_create_users.rb
│ ├── 20160523202806_add_index_to_users_email.rb
│ ├── 20160523203059_add_password_digest_to_users.rb
│ ├── 20160602174637_add_remember_digest_to_users.rb
│ ├── 20160605021434_add_admin_to_users.rb
│ ├── 20160606194223_add_activation_to_users.rb
│ ├── 20160606233616_add_reset_to_users.rb
│ ├── 20160608164853_create_microposts.rb
│ ├── 20160608202205_add_picture_to_microposts.rb
│ ├── 20160609220802_create_relationships.rb
│ ├── 20160807112453_add_token_to_users.rb
│ └── 20160907183517_add_cache_counters.rb
├── schema.rb
└── seeds.rb
├── docs
├── .gitignore
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Vagrantfile
├── config.rb
├── deploy.sh
├── font-selection.json
└── source
│ ├── fonts
│ ├── slate.eot
│ ├── slate.svg
│ ├── slate.ttf
│ ├── slate.woff
│ └── slate.woff2
│ ├── images
│ ├── logo.png
│ └── navbar.png
│ ├── includes
│ ├── _feed.md
│ ├── _followers.md
│ ├── _followings.md
│ ├── _microposts.md
│ ├── _overview.md
│ ├── _sessions.md
│ └── _users.md
│ ├── index.html.md
│ ├── javascripts
│ ├── all.js
│ ├── all_nosearch.js
│ ├── app
│ │ ├── _lang.js
│ │ ├── _search.js
│ │ └── _toc.js
│ └── lib
│ │ ├── _energize.js
│ │ ├── _imagesloaded.min.js
│ │ ├── _jquery.highlight.js
│ │ ├── _jquery.js
│ │ ├── _jquery.tocify.js
│ │ ├── _jquery_ui.js
│ │ └── _lunr.js
│ ├── layouts
│ └── layout.erb
│ └── stylesheets
│ ├── _icon-font.scss
│ ├── _normalize.scss
│ ├── _variables.scss
│ ├── print.css.scss
│ └── screen.css.scss
├── lib
├── assets
│ └── .keep
└── tasks
│ ├── .keep
│ └── auto_annotate_models.rake
├── log
└── .keep
├── public
├── 404.html
├── 422.html
├── 500.html
├── api
│ └── v1
│ │ └── docs
│ │ ├── fonts
│ │ ├── slate.eot
│ │ ├── slate.svg
│ │ ├── slate.ttf
│ │ ├── slate.woff
│ │ └── slate.woff2
│ │ ├── images
│ │ ├── logo.png
│ │ └── navbar.png
│ │ ├── index.html
│ │ ├── javascripts
│ │ ├── all.js
│ │ └── all_nosearch.js
│ │ └── stylesheets
│ │ ├── print.css
│ │ └── screen.css
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── favicon.ico
└── robots.txt
├── spec
├── apis
│ └── resource
│ │ ├── feeds
│ │ └── show_spec.rb
│ │ ├── followers
│ │ ├── destroy_spec.rb
│ │ └── index_spec.rb
│ │ ├── followings
│ │ ├── create_spec.rb
│ │ ├── destroy_spec.rb
│ │ └── index_spec.rb
│ │ ├── microposts
│ │ ├── create_spec.rb
│ │ ├── destroy_spec.rb
│ │ ├── index_spec.rb
│ │ ├── show_spec.rb
│ │ └── update_spec.rb
│ │ ├── sessions
│ │ ├── create_spec.rb
│ │ └── show_spec.rb
│ │ └── users
│ │ ├── activate_spec.rb
│ │ ├── create_spec.rb
│ │ ├── destroy_spec.rb
│ │ ├── index_spec.rb
│ │ ├── show_spec.rb
│ │ └── update_spec.rb
├── factories
│ ├── micropost.rb
│ ├── relationships.rb
│ └── users.rb
├── rails_helper.rb
├── schemas
│ ├── admin
│ │ ├── micropost.json
│ │ ├── microposts.json
│ │ ├── user.json
│ │ └── users.json
│ ├── errors.json
│ ├── guest
│ │ ├── user.json
│ │ └── users.json
│ └── regular
│ │ ├── micropost.json
│ │ ├── microposts.json
│ │ ├── session.json
│ │ ├── user.json
│ │ └── users.json
├── spec_helper.rb
└── support
│ ├── api_helpers.rb
│ ├── authentication_helper.rb
│ ├── database_cleaner.rb
│ ├── factory_girl.rb
│ └── rack_helper.rb
├── test
├── controllers
│ ├── .keep
│ ├── microposts_controller_test.rb
│ ├── relationships_controller_test.rb
│ ├── sessions_controller_test.rb
│ ├── static_pages_controller_test.rb
│ └── users_controller_test.rb
├── fixtures
│ ├── .keep
│ ├── files
│ │ └── .keep
│ ├── microposts.yml
│ ├── relationships.yml
│ └── users.yml
├── helpers
│ ├── .keep
│ └── sessions_helper_test.rb
├── integration
│ ├── .keep
│ ├── following_test.rb
│ ├── microposts_interface_test.rb
│ ├── password_resets_test.rb
│ ├── site_layout_test.rb
│ ├── users_edit_test.rb
│ ├── users_index_test.rb
│ ├── users_login_test.rb
│ ├── users_profile_test.rb
│ └── users_signup_test.rb
├── mailers
│ ├── .keep
│ ├── previews
│ │ └── user_mailer_preview.rb
│ └── user_mailer_test.rb
├── models
│ ├── .keep
│ ├── micropost_test.rb
│ ├── relationship_test.rb
│ └── user_test.rb
└── test_helper.rb
├── tmp
└── .keep
└── vendor
└── assets
├── javascripts
└── .keep
└── stylesheets
└── .keep
/.gitignore:
--------------------------------------------------------------------------------
1 | # 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 the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*
16 | /tmp/*
17 | !/log/.keep
18 | !/tmp/.keep
19 |
20 | # Ignore Byebug command history file.
21 | .byebug_history
22 |
23 | # Ignore Spring files.
24 | /spring/*.pid
25 |
26 | # Ignore uploaded test images.
27 | /public/uploads
28 | .envrc
29 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.3.3
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | ruby '2.3.3'
4 |
5 | gem 'rails', '5.0.0'
6 | gem 'bcrypt', '3.1.11'
7 | gem 'faker', '1.6.3'
8 | gem 'carrierwave', '0.11.2'
9 | gem 'mini_magick', '4.5.1'
10 | gem 'fog', '1.38.0'
11 | gem 'will_paginate', '3.1.0'
12 | gem 'bootstrap-will_paginate', '0.0.10'
13 | gem 'bootstrap-sass', '3.3.6'
14 | gem 'puma', '3.4.0'
15 | gem 'sass-rails', '5.0.5'
16 | gem 'uglifier', '3.0.0'
17 | gem 'coffee-rails', '4.2.1'
18 | gem 'jquery-rails', '4.1.1'
19 | gem 'turbolinks', '5.0.0'
20 | gem 'jbuilder', '2.4.1'
21 |
22 | group :development, :test do
23 | gem 'sqlite3', '1.3.11'
24 | gem 'byebug', '9.0.0', platform: :mri
25 | end
26 |
27 | group :development do
28 | gem 'web-console', '3.1.1'
29 | gem 'listen', '3.0.8'
30 | gem 'spring', '1.7.2'
31 | gem 'spring-watcher-listen', '2.0.0'
32 | gem 'annotate'
33 | end
34 |
35 | group :test do
36 | gem 'rails-controller-testing', '0.1.1'
37 | gem 'minitest-reporters', '1.1.9'
38 | gem 'guard', '2.13.0'
39 | gem 'guard-minitest', '2.4.4'
40 | end
41 |
42 | group :production do
43 | gem 'pg', '0.18.4'
44 | end
45 |
46 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
47 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
48 |
49 | #gems added for API development..
50 |
51 | gem 'pundit'
52 | gem 'active_model_serializers', github: 'rails-api/active_model_serializers'
53 | gem 'active_hash_relation', '~> 1.4.0'
54 | gem 'rack-cors', :require => 'rack/cors'
55 | gem 'flexible_permissions'
56 | gem 'rack-attack'
57 | gem 'redis-activesupport'
58 |
59 | group :development, :test do
60 | gem 'rspec-rails', '~> 3.5'
61 | gem 'rspec-api_helpers', '1.0.3'
62 | gem 'database_cleaner'
63 | gem 'factory_girl_rails'
64 | gem 'rspec-json_schema', :git => "git://github.com/blazed/rspec-json_schema.git"
65 | gem 'pry-rails'
66 | end
67 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # Defines the matching rules for Guard.
2 | guard :minitest, spring: true, all_on_start: false do
3 | watch(%r{^test/(.*)/?(.*)_test\.rb$})
4 | watch('test/test_helper.rb') { 'test' }
5 | watch('config/routes.rb') { integration_tests }
6 | watch(%r{^app/models/(.*?)\.rb$}) do |matches|
7 | "test/models/#{matches[1]}_test.rb"
8 | end
9 | watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
10 | resource_tests(matches[1])
11 | end
12 | watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
13 | ["test/controllers/#{matches[1]}_controller_test.rb"] +
14 | integration_tests(matches[1])
15 | end
16 | watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
17 | integration_tests(matches[1])
18 | end
19 | watch('app/views/layouts/application.html.erb') do
20 | 'test/integration/site_layout_test.rb'
21 | end
22 | watch('app/helpers/sessions_helper.rb') do
23 | integration_tests << 'test/helpers/sessions_helper_test.rb'
24 | end
25 | watch('app/controllers/sessions_controller.rb') do
26 | ['test/controllers/sessions_controller_test.rb',
27 | 'test/integration/users_login_test.rb']
28 | end
29 | watch('app/controllers/account_activations_controller.rb') do
30 | 'test/integration/users_signup_test.rb'
31 | end
32 | watch(%r{app/views/users/*}) do
33 | resource_tests('users') +
34 | ['test/integration/microposts_interface_test.rb']
35 | end
36 | end
37 |
38 | # Returns the integration tests corresponding to the given resource.
39 | def integration_tests(resource = :all)
40 | if resource == :all
41 | Dir["test/integration/*"]
42 | else
43 | Dir["test/integration/#{resource}_*.rb"]
44 | end
45 | end
46 |
47 | # Returns the controller tests corresponding to the given resource.
48 | def controller_test(resource)
49 | "test/controllers/#{resource}_controller_test.rb"
50 | end
51 |
52 | # Returns all tests for the given resource.
53 | def resource_tests(resource)
54 | integration_tests(resource) << controller_test(resource)
55 | end
56 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | All source code in the [Ruby on Rails Tutorial](http://railstutorial.org/) is available jointly under the MIT License and the Beerware License.
2 |
3 | ```
4 | The MIT License
5 |
6 | Copyright (c) 2016 Michael Hartl
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 | ```
26 |
27 | ```
28 | THE BEERWARE LICENSE (Revision 42)
29 |
30 | Michael Hartl wrote this code. As long as you retain this notice you can do
31 | whatever you want with this stuff. If we meet some day, and you think this
32 | stuff is worth it, you can buy me a beer in return.
33 | ```
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec puma -C config/puma.rb
2 |
--------------------------------------------------------------------------------
/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 ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/images/kitten.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/assets/images/kitten.jpg
--------------------------------------------------------------------------------
/app/assets/images/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/assets/images/rails.png
--------------------------------------------------------------------------------
/app/assets/javascripts/account_activations.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | //= require jquery
2 | //= require jquery_ujs
3 | //= require bootstrap
4 | //= require turbolinks
5 | //= require_tree .
6 |
--------------------------------------------------------------------------------
/app/assets/javascripts/cable.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 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/app/assets/javascripts/microposts.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/password_resets.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/relationships.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/sessions.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/static_pages.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/users.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/account_activations.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the AccountActivations controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/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, vendor/assets/stylesheets,
6 | * or any plugin's 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/assets/stylesheets/microposts.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Microposts controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/password_resets.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the PasswordResets controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/relationships.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Relationships controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/sessions.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Sessions controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/static_pages.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the StaticPages controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/users.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Users controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
2 | module ApplicationCable
3 | class Channel < ActionCable::Channel::Base
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
2 | module ApplicationCable
3 | class Connection < ActionCable::Connection::Base
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/controllers/account_activations_controller.rb:
--------------------------------------------------------------------------------
1 | class AccountActivationsController < ApplicationController
2 |
3 | def edit
4 | user = User.find_by(email: params[:email])
5 | if user && !user.activated? && user.authenticated?(:activation, params[:id])
6 | user.activate
7 | log_in user
8 | flash[:success] = "Account activated!"
9 | redirect_to user
10 | else
11 | flash[:danger] = "Invalid activation link"
12 | redirect_to root_url
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/app/controllers/api/v1/feeds_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::FeedsController < Api::V1::BaseController
2 | before_action :load_resource
3 |
4 | def show
5 | auth_microposts = policy_scope(@feed)
6 |
7 | render jsonapi: auth_microposts.collection,
8 | each_serializer: Api::V1::MicropostSerializer,
9 | fields: {micropost: auth_microposts.fields(params[:fields])},
10 | meta: meta_attributes(auth_microposts.collection)
11 | end
12 |
13 | private
14 | def load_resource
15 | case params[:action].to_sym
16 | when :show
17 | @feed = paginate(User.find(params[:user_id]).feed)
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/followers_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::FollowersController < Api::V1::BaseController
2 | before_action :load_resource
3 |
4 | def index
5 | auth_followers = policy_scope(@followers)
6 |
7 | render jsonapi: auth_followers.collection,
8 | each_serializer: Api::V1::UserSerializer,
9 | fields: {users: auth_followers.fields(params[:fields]).concat(
10 | [:microposts, :followers, :followings]
11 | )},
12 | include: [],
13 | meta: meta_attributes(auth_followers.collection)
14 | end
15 |
16 | #remove a follower
17 | def destroy
18 | auth_follower = FollowerPolicy.new(current_user, @relationship).destroy?
19 |
20 | @relationship.destroy!
21 |
22 | render jsonapi: auth_follower.record, serializer: Api::V1::UserSerializer,
23 | fields: { users: auth_follower.fields(params[:fields])},
24 | include: []
25 | end
26 |
27 | private
28 | def load_resource
29 | case params[:action].to_sym
30 | when :index
31 | @followers = paginate(
32 | apply_filters(User.find(params[:user_id]).followers, params)
33 | )
34 | when :destroy
35 | @relationship = Relationship.find_by!(
36 | followed_id: params[:user_id],
37 | follower_id: params[:id]
38 | )
39 | end
40 | end
41 | end
42 |
43 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/followings_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::FollowingsController < Api::V1::BaseController
2 | before_action :load_resource
3 |
4 | def index
5 | auth_followings = policy_scope(@followings)
6 |
7 | render jsonapi: auth_followings.collection,
8 | each_serializer: Api::V1::UserSerializer,
9 | fields: {users: auth_followings.fields(params[:fields]).concat(
10 | [:microposts, :followers, :followings]
11 | )},
12 | include: [],
13 | meta: meta_attributes(auth_followings.collection)
14 | end
15 |
16 | #follow a user
17 | def create
18 | auth_following = FollowingPolicy.new(current_user, @relationship).create?
19 |
20 | @relationship.save!
21 |
22 | render jsonapi: auth_following.record, serializer: Api::V1::UserSerializer
23 | end
24 |
25 | #unfollow a user
26 | def destroy
27 | auth_following = FollowingPolicy.new(current_user, @relationship).destroy?
28 |
29 | @relationship.destroy!
30 |
31 | render jsonapi: auth_following.record, serializer: Api::V1::UserSerializer
32 | end
33 |
34 | private
35 | def load_resource
36 | case params[:action].to_sym
37 | when :index
38 | @followings = paginate(
39 | apply_filters(User.find(params[:user_id]).following, params)
40 | )
41 | when :create
42 | @relationship = Relationship.new(
43 | follower_id: params[:user_id],
44 | followed_id: params[:id]
45 | )
46 | when :destroy
47 | @relationship = Relationship.find_by!(
48 | follower_id: params[:user_id],
49 | followed_id: params[:id]
50 | )
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/microposts_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::MicropostsController < Api::V1::BaseController
2 | before_action :load_resource
3 |
4 | def index
5 | auth_microposts = policy_scope(@microposts)
6 |
7 | render jsonapi: auth_microposts.collection,
8 | each_serializer: Api::V1::MicropostSerializer,
9 | fields: {micropost: auth_microposts.fields(params[:fields])},
10 | meta: meta_attributes(auth_microposts.collection)
11 | end
12 |
13 | def show
14 | auth_micropost = authorize_with_permissions(@micropost)
15 |
16 | render jsonapi: auth_micropost.record,
17 | serializer: Api::V1::MicropostSerializer,
18 | fields: {micropost: auth_micropost.fields}
19 | end
20 |
21 | def create
22 | auth_micropost = authorize_with_permissions(@micropost)
23 |
24 | if @micropost.save
25 | render jsonapi: auth_micropost.record,
26 | serializer: Api::V1::MicropostSerializer,
27 | fields: {mircopost: auth_micropost.fields}, status: 201
28 | else
29 | invalid_resource!(@micropost.errors)
30 | end
31 | end
32 |
33 | def update
34 | auth_micropost = authorize_with_permissions(@micropost, :update?)
35 |
36 | if @micropost.update(update_params)
37 | render jsonapi: auth_micropost.record,
38 | serializer: Api::V1::MicropostSerializer,
39 | micropost: {user: auth_micropost.fields}
40 | else
41 | invalid_resource!(@micropost.errors)
42 | end
43 | end
44 |
45 | def destroy
46 | auth_micropost = authorize_with_permissions(@micropost, :destroy?)
47 |
48 | @micropost.destroy!
49 |
50 | render jsonapi: auth_micropost.record,
51 | serializer: Api::V1::MicropostSerializer,
52 | micropost: {user: auth_micropost.fields}
53 | end
54 |
55 | private
56 | def load_resource
57 | case params[:action].to_sym
58 | when :index
59 | @microposts = paginate(apply_filters(Micropost.all, params))
60 | when :create
61 | @micropost = Micropost.new(create_params)
62 | when :show, :update, :destroy
63 | @micropost = Micropost.find(params[:id])
64 | end
65 | end
66 |
67 | def create_params
68 | prms = normalized_params.permit(
69 | :content, :picture, :user_id
70 | )
71 | if prms[:user_id].nil? && params[:action].to_sym == :create
72 | prms[:user_id] = current_user&.id
73 | end
74 |
75 | return prms
76 | end
77 |
78 | def update_params
79 | create_params
80 | end
81 |
82 | def normalized_params
83 | ActionController::Parameters.new(
84 | ActiveModelSerializers::Deserialization.jsonapi_parse(params)
85 | )
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/root_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::RootController < Api::V1::BaseController
2 |
3 | def options
4 | return head :ok
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::SessionsController < Api::V1::BaseController
2 | before_action :load_resource
3 | skip_before_action :authenticate_user!, only: [:create]
4 |
5 | def create
6 | if @user
7 | render(
8 | jsonapi: @user, serializer: Api::V1::SessionSerializer,
9 | status: 201, include: [:user], scope: @user
10 | )
11 | else
12 | return api_error(status: 401, errors: 'Wrong password or username')
13 | end
14 | end
15 |
16 | def show
17 | authorize(@user)
18 |
19 | render(
20 | jsonapi: @user, serializer: Api::V1::SessionSerializer,
21 | status: 200, include: [:user], fields: {
22 | user: UserPolicy::Regular.new(@user).fields
23 | }
24 | )
25 | end
26 |
27 | private
28 | def create_params
29 | normalized_params.permit(:email, :password)
30 | end
31 |
32 | def load_resource
33 | case params[:action].to_sym
34 | when :create
35 | @user = User.find_by(
36 | email: create_params[:email]
37 | )&.authenticate(create_params[:password])
38 | when :show
39 | @user = User.find(params[:id])
40 | end
41 | end
42 |
43 | def normalized_params
44 | ActionController::Parameters.new(
45 | ActiveModelSerializers::Deserialization.jsonapi_parse(params)
46 | )
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery with: :exception
3 | include SessionsHelper
4 |
5 | private
6 |
7 | # Confirms a logged-in user.
8 | def logged_in_user
9 | unless logged_in?
10 | store_location
11 | flash[:danger] = "Please log in."
12 | redirect_to login_url
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/concerns/custom_errors.rb:
--------------------------------------------------------------------------------
1 | module CustomErrors
2 | extend ActiveSupport::Concern
3 |
4 | class UnauthenticatedError < StandardError; end
5 | end
6 |
--------------------------------------------------------------------------------
/app/controllers/microposts_controller.rb:
--------------------------------------------------------------------------------
1 | class MicropostsController < ApplicationController
2 | before_action :logged_in_user, only: [:create, :destroy]
3 | before_action :correct_user, only: :destroy
4 |
5 | def create
6 | @micropost = current_user.microposts.build(micropost_params)
7 | if @micropost.save
8 | flash[:success] = "Micropost created!"
9 | redirect_to root_url
10 | else
11 | @feed_items = []
12 | render 'static_pages/home'
13 | end
14 | end
15 |
16 | def destroy
17 | @micropost.destroy
18 | flash[:success] = "Micropost deleted"
19 | redirect_to request.referrer || root_url
20 | end
21 |
22 | private
23 |
24 | def micropost_params
25 | params.require(:micropost).permit(:content, :picture)
26 | end
27 | def correct_user
28 | @micropost = current_user.microposts.find_by(id: params[:id])
29 | redirect_to root_url if @micropost.nil?
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/app/controllers/password_resets_controller.rb:
--------------------------------------------------------------------------------
1 | class PasswordResetsController < ApplicationController
2 | before_action :get_user, only: [:edit, :update]
3 | before_action :valid_user, only: [:edit, :update]
4 | before_action :check_expiration, only: [:edit, :update] # Case (1)
5 |
6 | def new
7 | end
8 |
9 | def create
10 | @user = User.find_by(email: params[:password_reset][:email].downcase)
11 | if @user
12 | @user.create_reset_digest
13 | @user.send_password_reset_email
14 | flash[:info] = "Email sent with password reset instructions"
15 | redirect_to root_url
16 | else
17 | flash.now[:danger] = "Email address not found"
18 | render 'new'
19 | end
20 | end
21 |
22 | def edit
23 | end
24 |
25 | def update
26 | if params[:user][:password].empty? # Case (3)
27 | @user.errors.add(:password, "can't be empty")
28 | render 'edit'
29 | elsif @user.update_attributes(user_params) # Case (4)
30 | log_in @user
31 | flash[:success] = "Password has been reset."
32 | redirect_to @user
33 | else
34 | render 'edit' # Case (2)
35 | end
36 | end
37 |
38 | private
39 |
40 | def user_params
41 | params.require(:user).permit(:password, :password_confirmation)
42 | end
43 |
44 | # Before filters
45 |
46 | def get_user
47 | @user = User.find_by(email: params[:email])
48 | end
49 |
50 | # Confirms a valid user.
51 | def valid_user
52 | unless (@user && @user.activated? &&
53 | @user.authenticated?(:reset, params[:id]))
54 | redirect_to root_url
55 | end
56 | end
57 |
58 | # Checks expiration of reset token.
59 | def check_expiration
60 | if @user.password_reset_expired?
61 | flash[:danger] = "Password reset has expired."
62 | redirect_to new_password_reset_url
63 | end
64 | end
65 | end
--------------------------------------------------------------------------------
/app/controllers/relationships_controller.rb:
--------------------------------------------------------------------------------
1 | class RelationshipsController < ApplicationController
2 | before_action :logged_in_user
3 |
4 | def create
5 | @user = User.find(params[:followed_id])
6 | current_user.follow(@user)
7 | respond_to do |format|
8 | format.html { redirect_to @user }
9 | format.js
10 | end
11 | end
12 |
13 | def destroy
14 | @user = Relationship.find(params[:id]).followed
15 | current_user.unfollow(@user)
16 | respond_to do |format|
17 | format.html { redirect_to @user }
18 | format.js
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < ApplicationController
2 |
3 | def new
4 | end
5 |
6 | def create
7 | user = User.find_by(email: params[:session][:email].downcase)
8 | if user && user.authenticate(params[:session][:password])
9 | if user.activated?
10 | log_in user
11 | params[:session][:remember_me] == '1' ? remember(user) : forget(user)
12 | redirect_back_or user
13 | else
14 | message = "Account not activated. "
15 | message += "Check your email for the activation link."
16 | flash[:warning] = message
17 | redirect_to root_url
18 | end
19 | else
20 | flash.now[:danger] = 'Invalid email/password combination' # Not quite right!
21 | render 'new'
22 | end
23 | end
24 |
25 | def destroy
26 | log_out if logged_in?
27 | redirect_to root_url
28 | end
29 | end
--------------------------------------------------------------------------------
/app/controllers/static_pages_controller.rb:
--------------------------------------------------------------------------------
1 | class StaticPagesController < ApplicationController
2 |
3 | def home
4 | if logged_in?
5 | @micropost = current_user.microposts.build
6 | @feed_items = current_user.feed.paginate(page: params[:page])
7 | end
8 | end
9 |
10 | def help
11 | end
12 |
13 | def about
14 | end
15 |
16 | def contact
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | class UsersController < ApplicationController
2 | before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
3 | :following, :followers]
4 | before_action :correct_user, only: [:edit, :update]
5 | before_action :admin_user, only: :destroy
6 |
7 | def index
8 | @users = User.paginate(page: params[:page])
9 | end
10 |
11 | def show
12 | @user = User.find(params[:id])
13 | @microposts = @user.microposts.paginate(page: params[:page])
14 | end
15 |
16 | def new
17 | @user = User.new
18 | end
19 |
20 | def create
21 | @user = User.new(user_params)
22 | if @user.save
23 | @user.send_activation_email
24 | flash[:info] = "Please check your email to activate your account."
25 | redirect_to root_url
26 | else
27 | render 'new'
28 | end
29 | end
30 |
31 | def edit
32 | @user = User.find(params[:id])
33 | end
34 |
35 | def update
36 | @user = User.find(params[:id])
37 | if @user.update_attributes(user_params)
38 | flash[:success] = "Profile updated"
39 | redirect_to @user
40 | else
41 | render 'edit'
42 | end
43 | end
44 |
45 | def destroy
46 | User.find(params[:id]).destroy
47 | flash[:success] = "User deleted"
48 | redirect_to users_url
49 | end
50 |
51 | def following
52 | @title = "Following"
53 | @user = User.find(params[:id])
54 | @users = @user.following.paginate(page: params[:page])
55 | render 'show_follow'
56 | end
57 |
58 | def followers
59 | @title = "Followers"
60 | @user = User.find(params[:id])
61 | @users = @user.followers.paginate(page: params[:page])
62 | render 'show_follow'
63 | end
64 |
65 | private
66 |
67 | def user_params
68 | params.require(:user).permit(:name, :email, :password,
69 | :password_confirmation)
70 | end
71 |
72 | # Before filters
73 |
74 | # Confirms the correct user.
75 | def correct_user
76 | @user = User.find(params[:id])
77 | redirect_to(root_url) unless current_user?(@user)
78 | end
79 |
80 | # Confirms an admin user.
81 | def admin_user
82 | redirect_to(root_url) unless current_user.admin?
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/app/helpers/account_activations_helper.rb:
--------------------------------------------------------------------------------
1 | module AccountActivationsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 |
3 | # Returns the full title on a per-page basis.
4 | def full_title(page_title = '')
5 | base_title = "Ruby on Rails Tutorial Sample App"
6 | if page_title.empty?
7 | base_title
8 | else
9 | page_title + " | " + base_title
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/helpers/microposts_helper.rb:
--------------------------------------------------------------------------------
1 | module MicropostsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/password_resets_helper.rb:
--------------------------------------------------------------------------------
1 | module PasswordResetsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/relationships_helper.rb:
--------------------------------------------------------------------------------
1 | module RelationshipsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 |
3 | # Logs in the given user.
4 | def log_in(user)
5 | session[:user_id] = user.id
6 | end
7 |
8 | # Remembers a user in a persistent session.
9 | def remember(user)
10 | user.remember
11 | cookies.permanent.signed[:user_id] = user.id
12 | cookies.permanent[:remember_token] = user.remember_token
13 | end
14 |
15 | # Returns true if the given user is the current user.
16 | def current_user?(user)
17 | user == current_user
18 | end
19 |
20 | # Returns the user corresponding to the remember token cookie.
21 | def current_user
22 | if (user_id = session[:user_id])
23 | @current_user ||= User.find_by(id: user_id)
24 | elsif (user_id = cookies.signed[:user_id])
25 | user = User.find_by(id: user_id)
26 | if user && user.authenticated?(:remember, cookies[:remember_token])
27 | log_in user
28 | @current_user = user
29 | end
30 | end
31 | end
32 |
33 | # Returns true if the user is logged in, false otherwise.
34 | def logged_in?
35 | !current_user.nil?
36 | end
37 |
38 | # Forgets a persistent session.
39 | def forget(user)
40 | user.forget
41 | cookies.delete(:user_id)
42 | cookies.delete(:remember_token)
43 | end
44 |
45 | # Logs out the current user.
46 | def log_out
47 | forget(current_user)
48 | session.delete(:user_id)
49 | @current_user = nil
50 | end
51 |
52 | # Redirects to stored location (or to the default).
53 | def redirect_back_or(default)
54 | redirect_to(session[:forwarding_url] || default)
55 | session.delete(:forwarding_url)
56 | end
57 |
58 | # Stores the URL trying to be accessed.
59 | def store_location
60 | session[:forwarding_url] = request.original_url if request.get?
61 | end
62 | end
--------------------------------------------------------------------------------
/app/helpers/static_pages_helper.rb:
--------------------------------------------------------------------------------
1 | module StaticPagesHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 |
3 | # Returns the Gravatar for the given user.
4 | def gravatar_for(user, options = { size: 80 })
5 | gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
6 | size = options[:size]
7 | gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
8 | image_tag(gravatar_url, alt: user.name, class: "gravatar")
9 | end
10 | end
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: "noreply@example.com"
3 | layout 'mailer'
4 | end
--------------------------------------------------------------------------------
/app/mailers/user_mailer.rb:
--------------------------------------------------------------------------------
1 | class UserMailer < ApplicationMailer
2 | helper_method :ember_activation_url
3 |
4 | def account_activation(user)
5 | @user = user
6 | mail to: user.email, subject: "Account activation"
7 | end
8 |
9 | def ember_account_activation(user)
10 | @user = user
11 | mail to: user.email, subject: "Account activation"
12 | end
13 |
14 | def password_reset(user)
15 | @user = user
16 | mail to: user.email, subject: "Password reset"
17 | end
18 |
19 | def ember_activation_url(token, email)
20 | "#{Rails.application.secrets.ember_activation_url}?token=#{token}&email=#{email}".html_safe
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/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/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/micropost.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: microposts
4 | #
5 | # id :integer not null, primary key
6 | # content :text
7 | # picture :string
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | # user_id :integer
11 | #
12 | # Indexes
13 | #
14 | # index_microposts_on_user_id (user_id)
15 | #
16 |
17 | class Micropost < ApplicationRecord
18 | belongs_to :user, counter_cache: true
19 |
20 | default_scope -> { order(created_at: :desc) }
21 | mount_uploader :picture, PictureUploader
22 | validates :user_id, presence: true
23 | validates :content, presence: true, length: { maximum: 140 }
24 | validate :picture_size
25 |
26 | private
27 |
28 | # Validates the size of an uploaded picture.
29 | def picture_size
30 | if picture.size > 5.megabytes
31 | errors.add(:picture, "should be less than 5MB")
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/app/models/relationship.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: relationships
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # followed_id :integer
9 | # follower_id :integer
10 | #
11 | # Indexes
12 | #
13 | # index_relationships_on_followed_id (followed_id)
14 | # index_relationships_on_follower_id (follower_id)
15 | # index_relationships_on_follower_id_and_followed_id (follower_id,followed_id) UNIQUE
16 | #
17 |
18 | class Relationship < ApplicationRecord
19 | belongs_to :follower, class_name: "User", counter_cache: :followings_count
20 | belongs_to :followed, class_name: "User", counter_cache: :followers_count
21 |
22 | validates :follower_id, presence: true
23 | validates :followed_id, presence: true
24 | end
25 |
--------------------------------------------------------------------------------
/app/policies/application_policy.rb:
--------------------------------------------------------------------------------
1 | class ApplicationPolicy
2 | attr_reader :user, :record
3 |
4 | def initialize(user, record)
5 | @user = user
6 | @record = record
7 | end
8 |
9 | def index?
10 | true
11 | end
12 |
13 | def show?
14 | scope.where(id: record.id).exists?
15 | end
16 |
17 | def create?
18 | false
19 | end
20 |
21 | def new?
22 | create?
23 | end
24 |
25 | def update?
26 | false
27 | end
28 |
29 | def edit?
30 | update?
31 | end
32 |
33 | def destroy?
34 | false
35 | end
36 |
37 | def scope
38 | Pundit.policy_scope!(user, record.class)
39 | end
40 |
41 | class Scope
42 | attr_reader :user, :scope
43 |
44 | def initialize(user, scope)
45 | @user = user
46 | @scope = scope
47 | end
48 |
49 | def resolve
50 | scope
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/app/policies/follower_policy.rb:
--------------------------------------------------------------------------------
1 | class FollowerPolicy < ApplicationPolicy
2 | def destroy?
3 | raise Pundit::NotAuthorizedError unless record.followed_id == user.id
4 | return Regular.new(record.follower)
5 | end
6 |
7 | class Scope < Scope
8 | def resolve
9 | return Regular.new(scope, User)
10 | end
11 | end
12 |
13 | class Regular < FlexiblePermissions::Base
14 | end
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/app/policies/following_policy.rb:
--------------------------------------------------------------------------------
1 | class FollowingPolicy < ApplicationPolicy
2 | def create?
3 | raise Pundit::NotAuthorizedError unless record.follower_id == user.id
4 |
5 | return Regular.new(record.followed)
6 | end
7 |
8 | def destroy?
9 | raise Pundit::NotAuthorizedError unless record.follower_id == user.id
10 |
11 | return Regular.new(record.followed)
12 | end
13 |
14 | class Scope < Scope
15 | def resolve
16 | return Regular.new(scope, User)
17 | end
18 | end
19 |
20 | class Regular < UserPolicy::Regular
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/policies/micropost_policy.rb:
--------------------------------------------------------------------------------
1 | class MicropostPolicy < ApplicationPolicy
2 | def create?
3 | return Regular.new(record)
4 | end
5 |
6 | def show?
7 | return Regular.new(record)
8 | end
9 |
10 | def update?
11 | return Regular.new(record)
12 | end
13 |
14 | def destroy?
15 | return Regular.new(record)
16 | end
17 |
18 | class Scope < Scope
19 | def resolve
20 | return Regular.new(scope, Micropost)
21 | end
22 | end
23 |
24 | class Admin < FlexiblePermissions::Base
25 | class Fields < self::Fields
26 | def permitted
27 | super + [
28 | :links
29 | ] - [
30 | :picture
31 | ]
32 | end
33 | end
34 |
35 | class Includes < self::Includes
36 | def default
37 | []
38 | end
39 | end
40 | end
41 |
42 | class Regular < Admin
43 | class Fields < self::Fields
44 | def permitted
45 | super - [
46 | :update_at
47 | ]
48 | end
49 | end
50 | end
51 | end
52 |
53 |
--------------------------------------------------------------------------------
/app/policies/user_policy.rb:
--------------------------------------------------------------------------------
1 | class UserPolicy < ApplicationPolicy
2 | def create?
3 | return Regular.new(record)
4 | end
5 |
6 | def show?
7 | return Guest.new(record) unless user
8 | return Admin.new(record) if user.admin?
9 | return Regular.new(record)
10 | end
11 |
12 | def update?
13 | raise Pundit::NotAuthorizedError unless user
14 | return Admin.new(record) if user.admin?
15 | return Regular.new(record)
16 | end
17 |
18 | def destroy?
19 | raise Pundit::NotAuthorizedError unless user
20 | return Admin.new(record) if user.admin?
21 | return Regular.new(record)
22 | end
23 |
24 | def activate?
25 | raise Pundit::NotAuthorizedError unless record.is_a? User
26 | return Admin.new(record) if record.admin?
27 | return Regular.new(record)
28 | end
29 |
30 | class Scope < Scope
31 | def resolve
32 | return Guest.new(scope, User) unless user
33 | return Admin.new(scope, User) if user.admin?
34 | return Regular.new(scope, User)
35 | end
36 | end
37 |
38 | class Admin < FlexiblePermissions::Base
39 | class Fields < self::Fields
40 | def permitted
41 | super + [
42 | :links, :following_state, :follower_state
43 | ]
44 | end
45 | end
46 |
47 | class Includes < self::Includes
48 | def permitted
49 | super + [:feed]
50 | end
51 |
52 | def transformations
53 | {following: :followings}
54 | end
55 | end
56 | end
57 |
58 | class Regular < Admin
59 | class Fields < self::Fields
60 | def permitted
61 | super - [
62 | :activated, :activated_at, :activation_digest, :admin,
63 | :password_digest, :remember_digest, :reset_digest, :reset_sent_at,
64 | :token, :updated_at,
65 | ]
66 | end
67 | end
68 | end
69 |
70 | class Guest < Regular
71 | class Fields < self::Fields
72 | def permitted
73 | super - [
74 | :following_state, :follower_state, :email, :microposts_count,
75 | :followers_count, :followings_count
76 | ]
77 | end
78 | end
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/app/serializers/api/v1/base_serializer.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::BaseSerializer < ActiveModel::Serializer
2 | include Rails.application.routes.url_helpers
3 |
4 | def created_at
5 | object.created_at.to_datetime.in_time_zone('UTC').iso8601 if object.created_at
6 | end
7 |
8 | def updated_at
9 | object.updated_at.to_datetime.in_time_zone('UTC').iso8601 if object.updated_at
10 | end
11 |
12 | def reset_sent_at
13 | object.published_at.to_datetime.in_time_zone('UTC').iso8601 if object.reset_sent_at
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/serializers/api/v1/error_serializer.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::ErrorSerializer
2 | UNKNOWN_ERROR = 'Something went wrong, no more info is available unforunately!'.freeze
3 | DEFAULT_POINTER = 'data'.freeze
4 |
5 | def initialize(status, errors)
6 | @status = status
7 | if errors.is_a? ActiveModel::Errors
8 | @errors = parse_am_errors(errors)
9 | else #it's an array or a string
10 | @errors = [errors].flatten
11 | end
12 | end
13 |
14 | def as_json
15 | {
16 | errors: errors
17 | }
18 | end
19 |
20 | def to_json
21 | as_json.to_json
22 | end
23 |
24 | private
25 |
26 | def parse_am_errors(errors)
27 | error_messages = errors.full_messages
28 |
29 | errors.map.with_index do |(k, v), i|
30 | ErrorDecorator.new(k, v, error_messages[i])
31 | end
32 | end
33 |
34 | def errors
35 | @errors.map do |error|
36 | {
37 | status: @status,
38 | title: normalize_title(error),
39 | detail: normalize_error(error),
40 | source: {
41 | pointer: error_pointer(error)
42 | }
43 | }
44 | end
45 | end
46 |
47 | def normalize_title(error)
48 | error.try(:title) || error.try(:to_s) || UNKNOWN_ERROR
49 | end
50 |
51 | def normalize_error(error)
52 | error.try(:details) || error.try(:to_s) || UNKNOWN_ERROR
53 | end
54 |
55 | def error_pointer(error)
56 | if error.respond_to?(:pointer)
57 | return error.pointer
58 | else
59 | return DEFAULT_POINTER
60 | end
61 | end
62 |
63 | class ErrorDecorator
64 | def initialize(key, value, message)
65 | @key, @value, @message = key, value, message
66 | end
67 |
68 | def title
69 | @value
70 | end
71 |
72 | def details
73 | @value
74 | end
75 |
76 | def to_s
77 | @message
78 | end
79 |
80 | def pointer
81 | "data/attributes/#{@key.to_s}"
82 | end
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/app/serializers/api/v1/micropost_serializer.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::MicropostSerializer < Api::V1::BaseSerializer
2 | attributes(*Micropost.attribute_names.map(&:to_sym))
3 |
4 | belongs_to :user, serializer: Api::V1::UserSerializer do
5 | include_data(false)
6 | link(:related) {api_v1_user_path(object.user_id)}
7 | end
8 |
9 | def picture
10 | object.picture.url
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/serializers/api/v1/session_serializer.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::SessionSerializer < Api::V1::BaseSerializer
2 | type :session
3 |
4 | attributes :email, :token, :user_id
5 |
6 | has_one :user, serializer: Api::V1::UserSerializer do
7 | link(:self) {api_v1_user_path(object.id)}
8 | link(:related) {api_v1_user_path(object.id)}
9 |
10 | object
11 | end
12 |
13 | def user
14 | object
15 | end
16 |
17 | def user_id
18 | object.id
19 | end
20 |
21 | def token
22 | object.token
23 | end
24 |
25 | def email
26 | object.email
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/serializers/api/v1/user_serializer.rb:
--------------------------------------------------------------------------------
1 | class Api::V1::UserSerializer < Api::V1::BaseSerializer
2 | attributes(*User.attribute_names.map(&:to_sym))
3 |
4 | attribute :following_state
5 | attribute :follower_state
6 |
7 | def following_state
8 | Relationship.where(
9 | follower_id: current_user.id,
10 | followed_id: object.id
11 | ).exists?
12 | end
13 |
14 | def follower_state
15 | Relationship.where(
16 | follower_id: object.id,
17 | followed_id: current_user.id
18 | ).exists?
19 | end
20 |
21 | has_one :feed, serializer: Api::V1::MicropostSerializer do
22 | include_data(false)
23 | link(:related) {api_v1_user_feed_path(user_id: object.id)}
24 | end
25 |
26 | has_many :microposts, serializer: Api::V1::MicropostSerializer do
27 | include_data(false)
28 | link(:related) {api_v1_microposts_path(user_id: object.id)}
29 | end
30 |
31 | has_many :followers, serializer: Api::V1::UserSerializer do
32 | include_data(false)
33 | link(:related) {api_v1_user_followers_path(user_id: object.id)}
34 | end
35 |
36 | has_many :followings, key: :followings, serializer: Api::V1::UserSerializer do
37 | include_data(false)
38 | link(:related) {api_v1_user_followings_path(user_id: object.id)}
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/app/uploaders/picture_uploader.rb:
--------------------------------------------------------------------------------
1 |
2 | class PictureUploader < CarrierWave::Uploader::Base
3 | include CarrierWave::MiniMagick
4 | process resize_to_limit: [400, 400]
5 |
6 | if Rails.env.production?
7 | storage :fog
8 | else
9 | storage :file
10 | end
11 |
12 | # Override the directory where uploaded files will be stored.
13 | # This is a sensible default for uploaders that are meant to be mounted:
14 | def store_dir
15 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
16 | end
17 |
18 | # Add a white list of extensions which are allowed to be uploaded.
19 | def extension_white_list
20 | %w(jpg jpeg gif png)
21 | end
22 | end
--------------------------------------------------------------------------------
/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/layouts/_header.html.erb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/layouts/_shim.html.erb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= full_title(yield(:title)) %>
5 | <%= csrf_meta_tags %>
6 | <%= stylesheet_link_tag 'application', media: 'all',
7 | 'data-turbolinks-track': 'reload' %>
8 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
9 | <%= render 'layouts/shim' %>
10 |
11 |
12 | <%= render 'layouts/header' %>
13 |
14 | <% flash.each do |message_type, message| %>
15 |
<%= message %>
16 | <% end %>
17 | <%= yield %>
18 | <%= render 'layouts/footer' %>
19 | <%= debug(params) if Rails.env.development? %>
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/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/microposts/_micropost.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
3 | <%= link_to micropost.user.name, micropost.user %>
4 |
5 | <%= micropost.content %>
6 | <%= image_tag micropost.picture.url if micropost.picture? %>
7 |
8 |
9 | Posted <%= time_ago_in_words(micropost.created_at) %> ago.
10 | <% if current_user?(micropost.user) %>
11 | <%= link_to "delete", micropost, method: :delete,
12 | data: { confirm: "You sure?" } %>
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/app/views/password_resets/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Reset password') %>
2 | Password reset
3 |
4 |
5 |
6 | <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
7 | <%= render 'shared/error_messages', object: f.object %>
8 |
9 | <%= hidden_field_tag :email, @user.email %>
10 |
11 | <%= f.label :password %>
12 | <%= f.password_field :password, class: 'form-control' %>
13 |
14 | <%= f.label :password_confirmation, "Confirmation" %>
15 | <%= f.password_field :password_confirmation, class: 'form-control' %>
16 |
17 | <%= f.submit "Update password", class: "btn btn-primary" %>
18 | <% end %>
19 |
20 |
--------------------------------------------------------------------------------
/app/views/password_resets/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Forgot password") %>
2 | Forgot password
3 |
4 |
5 |
6 | <%= form_for(:password_reset, url: password_resets_path) do |f| %>
7 | <%= f.label :email %>
8 | <%= f.email_field :email, class: 'form-control' %>
9 |
10 | <%= f.submit "Submit", class: "btn btn-primary" %>
11 | <% end %>
12 |
13 |
--------------------------------------------------------------------------------
/app/views/relationships/create.js.erb:
--------------------------------------------------------------------------------
1 | $("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
2 | $("#followers").html('<%= @user.followers.count %>');
--------------------------------------------------------------------------------
/app/views/relationships/destroy.js.erb:
--------------------------------------------------------------------------------
1 | $("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
2 | $("#followers").html('<%= @user.followers.count %>');
--------------------------------------------------------------------------------
/app/views/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Log in") %>
2 | Log in
3 |
4 |
5 |
6 | <%= form_for(:session, url: login_path) do |f| %>
7 |
8 | <%= f.label :email %>
9 | <%= f.email_field :email, class: 'form-control' %>
10 |
11 | <%= f.label :password %>
12 | <%= link_to "(forgot password)", new_password_reset_path %>
13 | <%= f.password_field :password, class: 'form-control' %>
14 |
15 | <%= f.label :remember_me, class: "checkbox inline" do %>
16 | <%= f.check_box :remember_me %>
17 |
Remember me on this computer
18 | <% end %>
19 |
20 | <%= f.submit "Log in", class: "btn btn-primary" %>
21 | <% end %>
22 |
23 |
New user? <%= link_to "Sign up now!", signup_path %>
24 |
25 |
--------------------------------------------------------------------------------
/app/views/shared/_error_messages.html.erb:
--------------------------------------------------------------------------------
1 | <% if object.errors.any? %>
2 |
3 |
4 | The form contains <%= pluralize(object.errors.count, "error") %>.
5 |
6 |
7 | <% object.errors.full_messages.each do |msg| %>
8 | <%= msg %>
9 | <% end %>
10 |
11 |
12 | <% end %>
--------------------------------------------------------------------------------
/app/views/shared/_feed.html.erb:
--------------------------------------------------------------------------------
1 | <% if @feed_items.any? %>
2 |
3 | <%= render @feed_items %>
4 |
5 | <%= will_paginate @feed_items %>
6 | <% end %>
--------------------------------------------------------------------------------
/app/views/shared/_micropost_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(@micropost, html: { multipart: true }) do |f| %>
2 | <%= render 'shared/error_messages', object: f.object %>
3 |
4 | <%= f.text_area :content, placeholder: "Compose new micropost..." %>
5 |
6 | <%= f.submit "Post", class: "btn btn-primary" %>
7 |
8 | <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
9 |
10 | <% end %>
11 |
12 |
--------------------------------------------------------------------------------
/app/views/shared/_stats.html.erb:
--------------------------------------------------------------------------------
1 | <% @user ||= current_user %>
2 |
--------------------------------------------------------------------------------
/app/views/shared/_user_info.html.erb:
--------------------------------------------------------------------------------
1 | <%= link_to gravatar_for(current_user, size: 50), current_user %>
2 | <%= current_user.name %>
3 | <%= link_to "view my profile", current_user %>
4 | <%= pluralize(current_user.microposts.count, "micropost") %>
--------------------------------------------------------------------------------
/app/views/static_pages/about.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "About") %>
2 | About
3 |
4 | The Ruby on Rails
5 | Tutorial is a
6 | book and
7 | screencast series
8 | to teach web development with
9 | Ruby on Rails .
10 | This is the sample application for the tutorial.
11 |
--------------------------------------------------------------------------------
/app/views/static_pages/contact.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Contact') %>
2 | Contact
3 |
4 | Contact the Ruby on Rails Tutorial about the sample app at the
5 | contact page .
6 |
--------------------------------------------------------------------------------
/app/views/static_pages/help.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Help") %>
2 | Help
3 |
4 | Get help on the Ruby on Rails Tutorial at the
5 | Rails Tutorial help section .
6 | To get help on this sample app, see the
7 | Ruby on Rails Tutorial
8 | book .
9 |
--------------------------------------------------------------------------------
/app/views/static_pages/home.html.erb:
--------------------------------------------------------------------------------
1 | <% if logged_in? %>
2 |
3 |
4 |
5 | <%= render 'shared/user_info' %>
6 |
7 |
8 | <%= render 'shared/stats' %>
9 |
10 |
11 | <%= render 'shared/micropost_form' %>
12 |
13 |
14 |
15 |
Micropost Feed
16 | <%= render 'shared/feed' %>
17 |
18 |
19 | <% else %>
20 |
21 |
Welcome to the Sample App
22 |
23 |
24 | This is the home page for the
25 | Ruby on Rails Tutorial
26 | sample application.
27 |
28 |
29 | <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
30 |
31 |
32 | <%= link_to image_tag("rails.png", alt: "Rails logo"),
33 | 'http://rubyonrails.org/' %>
34 | <% end %>
--------------------------------------------------------------------------------
/app/views/user_mailer/account_activation.html.erb:
--------------------------------------------------------------------------------
1 | Sample App
2 |
3 | Hi <%= @user.name %>,
4 |
5 |
6 | Welcome to the Sample App! Click on the link below to activate your account:
7 |
8 |
9 | <%= link_to "Activate", edit_account_activation_url(@user.activation_token,
10 | email: @user.email) %>
--------------------------------------------------------------------------------
/app/views/user_mailer/account_activation.text.erb:
--------------------------------------------------------------------------------
1 | Hi <%= @user.name %>,
2 |
3 | Welcome to the Sample App! Click on the link below to activate your account:
4 |
5 | <%= edit_account_activation_url(@user.activation_token, email: @user.email) %>
--------------------------------------------------------------------------------
/app/views/user_mailer/ember_account_activation.html.erb:
--------------------------------------------------------------------------------
1 | Sample App
2 |
3 | Hi <%= @user.name %>,
4 |
5 |
6 | Welcome to the Sample App! Click on the link below to activate your account:
7 |
8 |
9 | <%= link_to "Activate", ember_activation_url(@user.activation_token, @user.email) %>
10 |
--------------------------------------------------------------------------------
/app/views/user_mailer/ember_account_activation.text.erb:
--------------------------------------------------------------------------------
1 | Hi <%= @user.name %>,
2 |
3 | Welcome to the Sample App! Click on the link below to activate your account:
4 |
5 | <%= link_to "Activate", ember_activation_url(@user.activation_token, @user.email) %>
6 |
--------------------------------------------------------------------------------
/app/views/user_mailer/password_reset.html.erb:
--------------------------------------------------------------------------------
1 | Password reset
2 |
3 | To reset your password click the link below:
4 |
5 | <%= link_to "Reset password", edit_password_reset_url(@user.reset_token,
6 | email: @user.email) %>
7 |
8 | This link will expire in two hours.
9 |
10 |
11 | If you did not request your password to be reset, please ignore this email and
12 | your password will stay as it is.
13 |
--------------------------------------------------------------------------------
/app/views/user_mailer/password_reset.text.erb:
--------------------------------------------------------------------------------
1 | To reset your password click the link below:
2 |
3 | <%= edit_password_reset_url(@user.reset_token, email: @user.email) %>
4 |
5 | This link will expire in two hours.
6 |
7 | If you did not request your password to be reset, please ignore this email and
8 | your password will stay as it is.
--------------------------------------------------------------------------------
/app/views/users/_follow.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
2 | <%= hidden_field_tag :followed_id, @user.id %>
3 | <%= f.submit "Follow", class: "btn btn-primary" %>
4 | <% end %>
--------------------------------------------------------------------------------
/app/views/users/_follow_form.html.erb:
--------------------------------------------------------------------------------
1 | <% unless current_user?(@user) %>
2 |
3 | <% if current_user.following?(@user) %>
4 | <%= render 'unfollow' %>
5 | <% else %>
6 | <%= render 'follow' %>
7 | <% end %>
8 |
9 | <% end %>
--------------------------------------------------------------------------------
/app/views/users/_unfollow.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
2 | html: { method: :delete },
3 | remote: true) do |f| %>
4 | <%= f.submit "Unfollow", class: "btn" %>
5 | <% end %>
--------------------------------------------------------------------------------
/app/views/users/_user.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= gravatar_for user, size: 50 %>
3 | <%= link_to user.name, user %>
4 | <% if current_user.admin? && !current_user?(user) %>
5 | | <%= link_to "delete", user, method: :delete,
6 | data: { confirm: "You sure?" } %>
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/app/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Edit user") %>
2 | Update your profile
3 |
4 |
5 |
6 | <%= form_for(@user) do |f| %>
7 | <%= render 'shared/error_messages', object: f.object %>
8 |
9 | <%= f.label :name %>
10 | <%= f.text_field :name, class: 'form-control' %>
11 |
12 | <%= f.label :email %>
13 | <%= f.email_field :email, class: 'form-control' %>
14 |
15 | <%= f.label :password %>
16 | <%= f.password_field :password, class: 'form-control' %>
17 |
18 | <%= f.label :password_confirmation, "Confirmation" %>
19 | <%= f.password_field :password_confirmation, class: 'form-control' %>
20 |
21 | <%= f.submit "Save changes", class: "btn btn-primary" %>
22 | <% end %>
23 |
24 |
25 | <%= gravatar_for @user %>
26 |
change
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'All users') %>
2 | All users
3 |
4 | <%= will_paginate %>
5 |
6 |
7 | <%= render @users %>
8 |
9 |
10 | <%= will_paginate %>
11 |
--------------------------------------------------------------------------------
/app/views/users/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Sign up') %>
2 | Sign up
3 |
4 |
5 |
6 | <%= form_for(@user) do |f| %>
7 | <%= render 'shared/error_messages', object: f.object %>
8 | <%= f.label :name %>
9 | <%= f.text_field :name, class: 'form-control' %>
10 |
11 | <%= f.label :email %>
12 | <%= f.email_field :email, class: 'form-control' %>
13 |
14 | <%= f.label :password %>
15 | <%= f.password_field :password, class: 'form-control' %>
16 |
17 | <%= f.label :password_confirmation, "Confirmation" %>
18 | <%= f.password_field :password_confirmation, class: 'form-control' %>
19 |
20 | <%= f.submit "Create my account", class: "btn btn-primary" %>
21 | <% end %>
22 |
23 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, @user.name) %>
2 |
3 |
4 |
5 |
6 | <%= gravatar_for @user %>
7 | <%= @user.name %>
8 |
9 |
10 |
11 | <%= render 'shared/stats' %>
12 |
13 |
14 |
15 | <%= render 'follow_form' if logged_in? %>
16 | <% if @user.microposts.any? %>
17 |
Microposts (<%= @user.microposts.count %>)
18 |
19 | <%= render @microposts %>
20 |
21 | <%= will_paginate @microposts %>
22 | <% end %>
23 |
24 |
--------------------------------------------------------------------------------
/app/views/users/show_follow.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, @title) %>
2 |
3 |
21 |
22 |
<%= @title %>
23 | <% if @users.any? %>
24 |
25 | <%= render @users %>
26 |
27 | <%= will_paginate %>
28 | <% end %>
29 |
30 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../config/application', __dir__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a starting point to setup your application.
15 | # Add necessary setup steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | # puts "\n== Copying sample files =="
22 | # unless File.exist?('config/database.yml')
23 | # cp 'config/database.yml.sample', 'config/database.yml'
24 | # end
25 |
26 | puts "\n== Preparing database =="
27 | system! 'bin/rails db:setup'
28 |
29 | puts "\n== Removing old logs and tempfiles =="
30 | system! 'bin/rails log:clear tmp:clear'
31 |
32 | puts "\n== Restarting application server =="
33 | system! 'bin/rails restart'
34 | end
35 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a way to update your development environment automatically.
15 | # Add necessary update steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | puts "\n== Updating database =="
22 | system! 'bin/rails db:migrate'
23 |
24 | puts "\n== Removing old logs and tempfiles =="
25 | system! 'bin/rails log:clear tmp:clear'
26 |
27 | puts "\n== Restarting application server =="
28 | system! 'bin/rails restart'
29 | end
30 |
--------------------------------------------------------------------------------
/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 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module SampleApp
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Include the authenticity token in remote forms.
16 | config.action_view.embed_authenticity_token_in_remote_forms = true
17 |
18 | config.middleware.insert_before 0, Rack::Cors do
19 | allow do
20 | origins '*'
21 | resource '*', headers: :any, methods: [
22 | :get, :post, :put, :patch, :delete, :options, :head
23 | ]
24 | end
25 | end
26 |
27 | config.middleware.use Rack::Attack
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | # Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket.
2 | production:
3 | adapter: redis
4 | url: redis://localhost:6379/1
5 |
6 | development:
7 | adapter: async
8 |
9 | test:
10 | adapter: async
11 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: postgresql
9 | pool: 5
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: rails5_tutorial_api_development
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: rails5_tutorial_api_test
22 |
23 | production:
24 | <<: *default
25 | database: rails5_tutorial_api
26 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/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 | if Rails.root.join('tmp/caching-dev.txt').exist?
17 | config.action_controller.perform_caching = true
18 |
19 | config.cache_store = :memory_store
20 | config.public_file_server.headers = {
21 | 'Cache-Control' => 'public, max-age=172800'
22 | }
23 | else
24 | config.action_controller.perform_caching = false
25 |
26 | config.cache_store = :null_store
27 | end
28 |
29 | config.action_mailer.raise_delivery_errors = true
30 | config.action_mailer.delivery_method = :test
31 | host = 'rails-tutorial-mhartl.c9users.io'
32 | config.action_mailer.default_url_options = { host: host, protocol: 'https' }
33 | config.action_mailer.perform_caching = false
34 |
35 | # Print deprecation notices to the Rails logger.
36 | config.active_support.deprecation = :log
37 |
38 | # Raise an error on page load if there are pending migrations.
39 | config.active_record.migration_error = :page_load
40 |
41 | # Debug mode disables concatenation and preprocessing of assets.
42 | # This option may cause significant delays in view rendering with a large
43 | # number of complex assets.
44 | config.assets.debug = true
45 |
46 | # Raises error for missing translations
47 | # config.action_view.raise_on_missing_translations = true
48 |
49 | # Use an evented file watcher to asynchronously detect changes in source code,
50 | # routes, locales, etc. This feature depends on the listen gem.
51 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
52 | end
53 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => 'public, max-age=3600'
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 | config.action_mailer.perform_caching = false
31 |
32 | # Tell Action Mailer not to deliver emails to the real world.
33 | # The :test delivery method accumulates sent emails in the
34 | # ActionMailer::Base.deliveries array.
35 | config.action_mailer.delivery_method = :test
36 | config.action_mailer.default_url_options = { host: 'example.com' }
37 |
38 | # Print deprecation notices to the stderr.
39 | config.active_support.deprecation = :stderr
40 |
41 | # Raises error for missing translations
42 | # config.action_view.raise_on_missing_translations = true
43 | end
44 |
--------------------------------------------------------------------------------
/config/initializers/active_model_serializers.rb:
--------------------------------------------------------------------------------
1 | ActiveModelSerializers.config.adapter = :json_api
2 | ActiveSupport.on_load(:action_controller) do
3 | require 'active_model_serializers/register_jsonapi_renderer'
4 | end
5 |
--------------------------------------------------------------------------------
/config/initializers/active_record_belongs_to_required_by_default.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Require `belongs_to` associations by default. This is a new Rails 5.0
4 | # default, so it is introduced as a configuration option to ensure that apps
5 | # made on earlier versions of Rails are not affected when upgrading.
6 | Rails.application.config.active_record.belongs_to_required_by_default = true
7 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ApplicationController.renderer.defaults.merge!(
4 | # http_host: 'example.org',
5 | # https: false
6 | # )
7 |
--------------------------------------------------------------------------------
/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 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/config/initializers/callback_terminator.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Do not halt callback chains when a callback returns false. This is a new
4 | # Rails 5.0 default, so it is introduced as a configuration option to ensure
5 | # that apps made with earlier versions of Rails are not affected when upgrading.
6 | ActiveSupport.halt_callback_chains_on_return_false = false
7 |
--------------------------------------------------------------------------------
/config/initializers/carrier_wave.rb:
--------------------------------------------------------------------------------
1 | if Rails.env.production? && ENV['S3_BUCKET']
2 | CarrierWave.configure do |config|
3 | config.fog_credentials = {
4 | # Configuration for Amazon S3
5 | :provider => 'AWS',
6 | :aws_access_key_id => ENV['S3_ACCESS_KEY'],
7 | :aws_secret_access_key => ENV['S3_SECRET_KEY']
8 | }
9 | config.fog_directory = ENV['S3_BUCKET']
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/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/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/per_form_csrf_tokens.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Enable per-form CSRF tokens.
4 | Rails.application.config.action_controller.per_form_csrf_tokens = true
5 |
--------------------------------------------------------------------------------
/config/initializers/rack_attack.rb:
--------------------------------------------------------------------------------
1 | class Rack::Attack
2 | redis = ENV['REDISTOGO_URL'] || 'localhost'
3 | Rack::Attack.cache.store = ActiveSupport::Cache::RedisStore.new(redis)
4 |
5 | throttle('req/ip', :limit => 1000, :period => 10.minutes) do |req|
6 | req.ip if req.path.starts_with?('/api/v1')
7 | end
8 | end
9 |
10 | Rack::Attack.throttled_response = lambda do |env|
11 | now = Time.now
12 | match_data = env['rack.attack.match_data']
13 |
14 | headers = {
15 | 'X-RateLimit-Limit' => match_data[:limit].to_s,
16 | 'X-RateLimit-Remaining' => '0',
17 | 'X-RateLimit-Reset' => (now + (match_data[:period] - now.to_i % match_data[:period])).to_s
18 | }
19 |
20 | [ 429, headers, [Api::V1::ErrorSerializer.new(429, 'Too many requests').to_json]]
21 | end
22 |
--------------------------------------------------------------------------------
/config/initializers/request_forgery_protection.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Enable origin-checking CSRF mitigation.
4 | Rails.application.config.action_controller.forgery_protection_origin_check = true
5 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_sample_app_session'
4 |
--------------------------------------------------------------------------------
/config/initializers/ssl_options.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure SSL options to enable HSTS with subdomains.
4 | Rails.application.config.ssl_options = { hsts: { subdomains: true } }
5 |
--------------------------------------------------------------------------------
/config/initializers/to_time_preserves_timezone.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Preserve the timezone of the receiver when calling to `to_time`.
4 | # Ruby 2.4 will change the behavior of `to_time` to preserve the timezone
5 | # when converting to an instance of `Time` instead of the previous behavior
6 | # of converting to the local system timezone.
7 | #
8 | # Rails 5.0 introduced this config option so that apps made with earlier
9 | # versions of Rails are not affected when upgrading.
10 | ActiveSupport.to_time_preserves_timezone = true
11 |
--------------------------------------------------------------------------------
/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 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | workers Integer(ENV['WEB_CONCURRENCY'] || 2)
2 | threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
3 | threads threads_count, threads_count
4 |
5 | preload_app!
6 |
7 | rackup DefaultRackup
8 | port ENV['PORT'] || 3000
9 | environment ENV['RACK_ENV'] || 'development'
10 |
11 | on_worker_boot do
12 | # Worker specific setup for Rails 4.1+
13 | # See: https://devcenter.heroku.com/articles/
14 | # deploying-rails-applications-with-the-puma-web-server#on-worker-boot
15 | ActiveRecord::Base.establish_connection
16 | end
17 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root 'static_pages#home'
3 | get '/help', to: 'static_pages#help'
4 | get '/about', to: 'static_pages#about'
5 | get '/contact', to: 'static_pages#contact'
6 | get '/signup', to: 'users#new'
7 | get '/login', to: 'sessions#new'
8 | post '/login', to: 'sessions#create'
9 | delete '/logout', to: 'sessions#destroy'
10 | resources :users do
11 | member do
12 | get :following, :followers
13 | end
14 | end
15 | resources :account_activations, only: [:edit]
16 | resources :password_resets, only: [:new, :create, :edit, :update]
17 | resources :microposts, only: [:create, :destroy]
18 | resources :relationships, only: [:create, :destroy]
19 |
20 | #api
21 | namespace :api do
22 | namespace :v1 do
23 | resources :sessions, only: [:create, :show]
24 |
25 | resources :users, only: [:index, :create, :show, :update, :destroy] do
26 | post :activate, on: :collection
27 | resources :followers, only: [:index, :destroy]
28 | resources :followings, only: [:index, :destroy] do
29 | post :create, on: :member
30 | end
31 | resource :feed, only: [:show]
32 | end
33 | resources :microposts, only: [:index, :create, :show, :update, :destroy]
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rails secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: 45ec0d9f13a6cc38fc2cfd0314fae312cbf9e8db5dc8485cba84fce8ae39c62944ad57e4dab04c7f89c6fc3cbc865fbd4ce93005b4aa2b47ed96712be1b1a28d
15 | ember_activation_url: <%= ENV['EMBER_ACTIVATION_URL'] %>
16 |
17 | test:
18 | secret_key_base: f76a37afd9d7f155210462ac50b966ace268ba7fee105d13dab09ddd56844cf6d4c47e6ffa57f088b2beb3db923a27779d5c45297f0f7aa1df48849cd00cea03
19 | ember_activation_url: <%= ENV['EMBER_ACTIVATION_URL'] %>
20 |
21 | # Do not keep production secrets in the repository,
22 | # instead read values from the environment.
23 | production:
24 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
25 | ember_activation_url: <%= ENV['EMBER_ACTIVATION_URL'] %>
26 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w(
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ).each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/db/migrate/20160523185459_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :users do |t|
4 | t.string :name
5 | t.string :email
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20160523202806_add_index_to_users_email.rb:
--------------------------------------------------------------------------------
1 | class AddIndexToUsersEmail < ActiveRecord::Migration[5.0]
2 | def change
3 | add_index :users, :email, unique: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160523203059_add_password_digest_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :password_digest, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160602174637_add_remember_digest_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddRememberDigestToUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :remember_digest, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160605021434_add_admin_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddAdminToUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :admin, :boolean, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160606194223_add_activation_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddActivationToUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :activation_digest, :string
4 | add_column :users, :activated, :boolean, default: false
5 | add_column :users, :activated_at, :datetime
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20160606233616_add_reset_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddResetToUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :reset_digest, :string
4 | add_column :users, :reset_sent_at, :datetime
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20160608164853_create_microposts.rb:
--------------------------------------------------------------------------------
1 | class CreateMicroposts < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :microposts do |t|
4 | t.text :content
5 | t.references :user, foreign_key: true
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20160608202205_add_picture_to_microposts.rb:
--------------------------------------------------------------------------------
1 | class AddPictureToMicroposts < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :microposts, :picture, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160609220802_create_relationships.rb:
--------------------------------------------------------------------------------
1 | class CreateRelationships < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :relationships do |t|
4 | t.integer :follower_id
5 | t.integer :followed_id
6 |
7 | t.timestamps
8 | end
9 | add_index :relationships, :follower_id
10 | add_index :relationships, :followed_id
11 | add_index :relationships, [:follower_id, :followed_id], unique: true end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20160807112453_add_token_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddTokenToUsers < ActiveRecord::Migration[5.0]
2 | def up
3 | add_column :users, :token, :string
4 |
5 | User.find_each{|user| user.save!}
6 |
7 | change_column_null :users, :token, false
8 | end
9 |
10 | def down
11 | remove_column :users, :token, :string
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20160907183517_add_cache_counters.rb:
--------------------------------------------------------------------------------
1 | class AddCacheCounters < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :microposts_count, :integer, :null => false, :default => 0
4 | add_column :users, :followers_count, :integer, :null => false, :default => 0
5 | add_column :users, :followings_count, :integer, :null => false, :default => 0
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/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 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 20160907183517) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "microposts", force: :cascade do |t|
19 | t.text "content"
20 | t.integer "user_id"
21 | t.datetime "created_at", null: false
22 | t.datetime "updated_at", null: false
23 | t.string "picture"
24 | t.index ["user_id"], name: "index_microposts_on_user_id", using: :btree
25 | end
26 |
27 | create_table "relationships", force: :cascade do |t|
28 | t.integer "follower_id"
29 | t.integer "followed_id"
30 | t.datetime "created_at", null: false
31 | t.datetime "updated_at", null: false
32 | t.index ["followed_id"], name: "index_relationships_on_followed_id", using: :btree
33 | t.index ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true, using: :btree
34 | t.index ["follower_id"], name: "index_relationships_on_follower_id", using: :btree
35 | end
36 |
37 | create_table "users", force: :cascade do |t|
38 | t.string "name"
39 | t.string "email"
40 | t.datetime "created_at", null: false
41 | t.datetime "updated_at", null: false
42 | t.string "password_digest"
43 | t.string "remember_digest"
44 | t.boolean "admin", default: false
45 | t.string "activation_digest"
46 | t.boolean "activated", default: false
47 | t.datetime "activated_at"
48 | t.string "reset_digest"
49 | t.datetime "reset_sent_at"
50 | t.string "token", null: false
51 | t.integer "microposts_count", default: 0, null: false
52 | t.integer "followers_count", default: 0, null: false
53 | t.integer "followings_count", default: 0, null: false
54 | t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
55 | end
56 |
57 | add_foreign_key "microposts", "users"
58 | end
59 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # Users
2 | User.create!(name: "Example User",
3 | email: "example@railstutorial.org",
4 | password: "foobar",
5 | password_confirmation: "foobar",
6 | admin: true,
7 | activated: true,
8 | activated_at: Time.zone.now)
9 |
10 | 99.times do |n|
11 | name = Faker::Name.name
12 | email = "example-#{n+1}@railstutorial.org"
13 | password = "password"
14 | User.create!(name: name,
15 | email: email,
16 | password: password,
17 | password_confirmation: password,
18 | activated: true,
19 | activated_at: Time.zone.now)
20 | end
21 |
22 | # Microposts
23 | users = User.order(:created_at).take(6)
24 | 50.times do
25 | content = Faker::Lorem.sentence(5)
26 | users.each { |user| user.microposts.create!(content: content) }
27 | end
28 |
29 | # Following relationships
30 | users = User.all
31 | user = users.first
32 | following = users[2..50]
33 | followers = users[3..40]
34 | following.each { |followed| user.follow(followed) }
35 | followers.each { |follower| follower.follow(user) }
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | coverage
6 | InstalledFiles
7 | lib/bundler/man
8 | pkg
9 | rdoc
10 | spec/reports
11 | test/tmp
12 | test/version_tmp
13 | tmp
14 | *.DS_STORE
15 | build/
16 | .cache
17 | .vagrant
18 | .sass-cache
19 |
20 | # YARD artifacts
21 | .yardoc
22 | _yardoc
23 | doc/
24 | .idea/
25 |
--------------------------------------------------------------------------------
/docs/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## Version 1.4.0
4 |
5 | *November 24, 2016*
6 |
7 | - Upgrade Middleman and Rouge gems, should hopefully solve a number of bugs
8 | - Update some links in README
9 | - Fix broken Vagrant startup script
10 | - Fix some problems with deploy.sh help message
11 | - Fix bug with language tabs not hiding properly if no error
12 | - Add `!default` to SASS variables
13 | - Fix bug with logo margin
14 | - Bump tested Ruby versions in .travis.yml
15 |
16 | ## Version 1.3.3
17 |
18 | *June 11, 2016*
19 |
20 | Documentation and example changes.
21 |
22 | ## Version 1.3.2
23 |
24 | *February 3, 2016*
25 |
26 | A small bugfix for slightly incorrect background colors on code samples in some cases.
27 |
28 | ## Version 1.3.1
29 |
30 | *January 31, 2016*
31 |
32 | A small bugfix for incorrect whitespace in code blocks.
33 |
34 | ## Version 1.3
35 |
36 | *January 27, 2016*
37 |
38 | We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs.
39 |
40 | Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages.
41 |
42 | ## Version 1.2
43 |
44 | *June 20, 2015*
45 |
46 | **Fixes:**
47 |
48 | - Remove crash on invalid languages
49 | - Update Tocify to scroll to the highlighted header in the Table of Contents
50 | - Fix variable leak and update search algorithms
51 | - Update Python examples to be valid Python
52 | - Update gems
53 | - More misc. bugfixes of Javascript errors
54 | - Add Dockerfile
55 | - Remove unused gems
56 | - Optimize images, fonts, and generated asset files
57 | - Add chinese font support
58 | - Remove RedCarpet header ID patch
59 | - Update language tabs to not disturb existing query strings
60 |
61 | ## Version 1.1
62 |
63 | *July 27, 2014*
64 |
65 | **Fixes:**
66 |
67 | - Finally, a fix for the redcarpet upgrade bug
68 |
69 | ## Version 1.0
70 |
71 | *July 2, 2014*
72 |
73 | [View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed)
74 |
75 | **Features:**
76 |
77 | - Responsive designs for phones and tablets
78 | - Started tagging versions
79 |
80 | **Fixes:**
81 |
82 | - Fixed 'unrecognized expression' error
83 | - Fixed #undefined hash bug
84 | - Fixed bug where the current language tab would be unselected
85 | - Fixed bug where tocify wouldn't highlight the current section while searching
86 | - Fixed bug where ids of header tags would have special characters that caused problems
87 | - Updated layout so that pages with disabled search wouldn't load search.js
88 | - Cleaned up Javascript
89 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Middleman
4 | gem 'middleman', '~>4.1.0'
5 | gem 'middleman-syntax', '~> 3.0.0'
6 | gem 'middleman-autoprefixer', '~> 2.7.0'
7 | gem "middleman-sprockets", "~> 4.0.0"
8 | gem 'rouge', '~> 2.0.5'
9 | gem 'redcarpet', '~> 3.3.2'
10 |
--------------------------------------------------------------------------------
/docs/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2008-2013 Concur Technologies, Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | not use this file except in compliance with the License. You may obtain
5 | a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | License for the specific language governing permissions and limitations
13 | under the License.
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Ruby on Rails API tutorial Readme
2 |
3 | [ ](https://app.codeship.com/projects/198686)
4 |
5 | This is the sample application for the
6 | [*Ruby on Rails Tutorial:
7 | Learn Web Development with Rails*](http://www.railstutorial.org/)
8 | by [Michael Hartl](http://www.michaelhartl.com/) **but with an API for the [Ember version](https://github.com/vasilakisfil/ember_on_rails5)**,
9 | used by the [api tutorial](https://github.com/vasilakisfil/rails5_api_tutorial).
10 |
11 | It's deployed [here](https://rails-tutorial-api.herokuapp.com/).
12 | Ember version is deployed [here](https://ember-on-rails-tutorial.herokuapp.com) based on this [repo](https://github.com/vasilakisfil/ember_on_rails5)
13 |
14 | If you are looking the Rails 4 version there is a [blog post](https://labs.kollegorna.se/blog/2015/04/build-an-api-now/)
15 |
16 | ## License
17 |
18 | All code added by me (vasilakisfil) is availabe under the MIT License.
19 | The rest is available jointly under the MIT License and the Beerware License. See [LICENSE.md](LICENSE.md) for details.
20 |
21 | ## Getting started
22 |
23 | To get started with the app, clone the repo and then install the needed gems:
24 |
25 | ```
26 | cd ~/tmp
27 | git clone https://github.com/vasilakisfil/rails5_api_tutorial.git
28 | cd rails5_api_tutorial
29 | bundle install
30 | bundle exec rake db:create #we use postgresql instead of sqlite3
31 | bundle exec rake db:migrate
32 | bundle exec rails s
33 | ```
34 |
35 | ## Contributing
36 |
37 | Bug reports and pull requests are welcome on GitHub at https://github.com/vasilakisfil/rails5_api_tutorial.
38 | This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
39 | the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
40 |
--------------------------------------------------------------------------------
/docs/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.configure(2) do |config|
2 | config.vm.box = "ubuntu/trusty64"
3 | config.vm.network :forwarded_port, guest: 4567, host: 4567
4 |
5 | config.vm.provision "bootstrap",
6 | type: "shell",
7 | inline: <<-SHELL
8 | sudo apt-get update
9 | sudo apt-get install -yq ruby2.0 ruby2.0-dev pkg-config build-essential nodejs git libxml2-dev libxslt-dev
10 | sudo apt-get autoremove -yq
11 | gem2.0 install --no-ri --no-rdoc bundler
12 | SHELL
13 |
14 | # add the local user git config to the vm
15 | config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
16 |
17 | config.vm.provision "install",
18 | type: "shell",
19 | privileged: false,
20 | inline: <<-SHELL
21 | echo "=============================================="
22 | echo "Installing app dependencies"
23 | cd /vagrant
24 | bundle config build.nokogiri --use-system-libraries
25 | bundle install
26 | SHELL
27 |
28 | config.vm.provision "run",
29 | type: "shell",
30 | privileged: false,
31 | run: "always",
32 | inline: <<-SHELL
33 | echo "=============================================="
34 | echo "Starting up middleman at http://localhost:4567"
35 | echo "If it does not come up, check the ~/middleman.log file for any error messages"
36 | cd /vagrant
37 | bundle exec middleman server --watcher-force-polling --watcher_latency=1 &> ~/middleman.log &
38 | SHELL
39 | end
40 |
--------------------------------------------------------------------------------
/docs/config.rb:
--------------------------------------------------------------------------------
1 | # Markdown
2 | set :markdown_engine, :redcarpet
3 | set :markdown,
4 | fenced_code_blocks: true,
5 | smartypants: true,
6 | disable_indented_code_blocks: true,
7 | prettify: true,
8 | tables: true,
9 | with_toc_data: true,
10 | no_intra_emphasis: true
11 |
12 | # Assets
13 | set :css_dir, 'stylesheets'
14 | set :js_dir, 'javascripts'
15 | set :images_dir, 'images'
16 | set :fonts_dir, 'fonts'
17 |
18 | # Activate the syntax highlighter
19 | activate :syntax
20 |
21 | activate :sprockets
22 |
23 | activate :autoprefixer do |config|
24 | config.browsers = ['last 2 version', 'Firefox ESR']
25 | config.cascade = false
26 | config.inline = true
27 | end
28 |
29 | # Github pages require relative links
30 | activate :relative_assets
31 | set :relative_links, true
32 |
33 | set :build_dir, '../public/api/v1/docs/'
34 |
35 | # Build Configuration
36 | configure :build do
37 | # If you're having trouble with Middleman hanging, commenting
38 | # out the following two lines has been known to help
39 | activate :minify_css
40 | activate :minify_javascript
41 | # activate :asset_hash
42 | # activate :gzip
43 | end
44 |
45 | # Deploy Configuration
46 | # If you want Middleman to listen on a different port, you can set that below
47 | set :port, 4567
48 |
--------------------------------------------------------------------------------
/docs/source/fonts/slate.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/fonts/slate.eot
--------------------------------------------------------------------------------
/docs/source/fonts/slate.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Generated by IcoMoon
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/source/fonts/slate.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/fonts/slate.ttf
--------------------------------------------------------------------------------
/docs/source/fonts/slate.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/fonts/slate.woff
--------------------------------------------------------------------------------
/docs/source/fonts/slate.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/fonts/slate.woff2
--------------------------------------------------------------------------------
/docs/source/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/images/logo.png
--------------------------------------------------------------------------------
/docs/source/images/navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/docs/source/images/navbar.png
--------------------------------------------------------------------------------
/docs/source/includes/_feed.md:
--------------------------------------------------------------------------------
1 | # Feed
2 |
3 | The feed of a user is a list of microposts of users she follows order by `created_at` in a descending order.
4 |
5 | ## Show Feed
6 | ```http
7 | GET /api/v1/users/1/followings HTTP/1.1
8 | Micropost-Agent: MyClient/1.0.0
9 | Accept: application/vnd.api+json
10 | ```
11 | ```http
12 | HTTP/1.1 200 OK
13 | {
14 | "data":[
15 | {
16 | "id":"349",
17 | "type":"microposts",
18 | "attributes":{
19 | "content":"test",
20 | "user-id":1,
21 | "created-at":"2016-11-19T18:56:55Z",
22 | "updated-at":"2016-11-19T18:56:55Z"
23 | },
24 | "relationships":{
25 | "user":{
26 | "links":{
27 | "related":"/api/v1/users/1"
28 | }
29 | }
30 | }
31 | }
32 | ],
33 | "links":{
34 | "self":"http://localhost:3000/api/v1/microposts?page%5Bnumber%5D=1\u0026page%5Bsize%5D=1\u0026per_page=1",
35 | "next":"http://localhost:3000/api/v1/microposts?page%5Bnumber%5D=2\u0026page%5Bsize%5D=1\u0026per_page=1",
36 | "last":"http://localhost:3000/api/v1/microposts?page%5Bnumber%5D=349\u0026page%5Bsize%5D=1\u0026per_page=1"
37 | },
38 | "meta":{
39 | "current-page":1,
40 | "next-page":2,
41 | "prev-page":null,
42 | "total-pages":349,
43 | "total-count":349
44 | }
45 | }
46 | ```
47 |
48 | If you want to filter the microposts, use the [microposts](#microposts) API.
49 |
--------------------------------------------------------------------------------
/docs/source/index.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: API Reference
3 |
4 | language_tabs:
5 | - http
6 |
7 | toc_footers:
8 | - Documentation Powered by Slate
9 |
10 | includes:
11 | - overview
12 | - sessions
13 | - users
14 | - microposts
15 | - followers
16 | - followings
17 | - feed
18 |
19 | search: true
20 | ---
21 |
22 | # Introduction
23 |
24 | Welcome to rails tutorial API.
25 | The implementation of the API can be found [here](https://github.com/vasilakisfil/rails5_api_tutorial). Using this API an Ember application is also built, found [here](https://github.com/vasilakisfil/ember_on_rails5).
26 |
27 |
28 | The following documents the V1 API.
29 |
--------------------------------------------------------------------------------
/docs/source/javascripts/all.js:
--------------------------------------------------------------------------------
1 | //= require ./lib/_energize
2 | //= require ./app/_lang
3 | //= require ./app/_search
4 | //= require ./app/_toc
5 |
--------------------------------------------------------------------------------
/docs/source/javascripts/all_nosearch.js:
--------------------------------------------------------------------------------
1 | //= require ./lib/_energize
2 | //= require ./app/_lang
3 | //= require ./app/_toc
4 |
--------------------------------------------------------------------------------
/docs/source/javascripts/app/_search.js:
--------------------------------------------------------------------------------
1 | //= require ../lib/_lunr
2 | //= require ../lib/_jquery
3 | //= require ../lib/_jquery.highlight
4 | (function () {
5 | 'use strict';
6 |
7 | var content, searchResults;
8 | var highlightOpts = { element: 'span', className: 'search-highlight' };
9 |
10 | var index = new lunr.Index();
11 |
12 | index.ref('id');
13 | index.field('title', { boost: 10 });
14 | index.field('body');
15 | index.pipeline.add(lunr.trimmer, lunr.stopWordFilter);
16 |
17 | $(populate);
18 | $(bind);
19 |
20 | function populate() {
21 | $('h1, h2').each(function() {
22 | var title = $(this);
23 | var body = title.nextUntil('h1, h2');
24 | index.add({
25 | id: title.prop('id'),
26 | title: title.text(),
27 | body: body.text()
28 | });
29 | });
30 | }
31 |
32 | function bind() {
33 | content = $('.content');
34 | searchResults = $('.search-results');
35 |
36 | $('#input-search').on('keyup', search);
37 | }
38 |
39 | function search(event) {
40 | unhighlight();
41 | searchResults.addClass('visible');
42 |
43 | // ESC clears the field
44 | if (event.keyCode === 27) this.value = '';
45 |
46 | if (this.value) {
47 | var results = index.search(this.value).filter(function(r) {
48 | return r.score > 0.0001;
49 | });
50 |
51 | if (results.length) {
52 | searchResults.empty();
53 | $.each(results, function (index, result) {
54 | var elem = document.getElementById(result.ref);
55 | searchResults.append("" + $(elem).text() + " ");
56 | });
57 | highlight.call(this);
58 | } else {
59 | searchResults.html(' ');
60 | $('.search-results li').text('No Results Found for "' + this.value + '"');
61 | }
62 | } else {
63 | unhighlight();
64 | searchResults.removeClass('visible');
65 | }
66 | }
67 |
68 | function highlight() {
69 | if (this.value) content.highlight(this.value, highlightOpts);
70 | }
71 |
72 | function unhighlight() {
73 | content.unhighlight(highlightOpts);
74 | }
75 | })();
76 |
--------------------------------------------------------------------------------
/docs/source/javascripts/app/_toc.js:
--------------------------------------------------------------------------------
1 | //= require ../lib/_jquery
2 | //= require ../lib/_jquery_ui
3 | //= require ../lib/_jquery.tocify
4 | //= require ../lib/_imagesloaded.min
5 | (function (global) {
6 | 'use strict';
7 |
8 | var closeToc = function() {
9 | $(".tocify-wrapper").removeClass('open');
10 | $("#nav-button").removeClass('open');
11 | };
12 |
13 | var makeToc = function() {
14 | global.toc = $("#toc").tocify({
15 | selectors: 'h1, h2',
16 | extendPage: false,
17 | theme: 'none',
18 | smoothScroll: false,
19 | showEffectSpeed: 0,
20 | hideEffectSpeed: 180,
21 | ignoreSelector: '.toc-ignore',
22 | highlightOffset: 60,
23 | scrollTo: -1,
24 | scrollHistory: true,
25 | hashGenerator: function (text, element) {
26 | return element.prop('id');
27 | }
28 | }).data('toc-tocify');
29 |
30 | $("#nav-button").click(function() {
31 | $(".tocify-wrapper").toggleClass('open');
32 | $("#nav-button").toggleClass('open');
33 | return false;
34 | });
35 |
36 | $(".page-wrapper").click(closeToc);
37 | $(".tocify-item").click(closeToc);
38 | };
39 |
40 | // Hack to make already open sections to start opened,
41 | // instead of displaying an ugly animation
42 | function animate() {
43 | setTimeout(function() {
44 | toc.setOption('showEffectSpeed', 180);
45 | }, 50);
46 | }
47 |
48 | $(function() {
49 | makeToc();
50 | animate();
51 | setupLanguages($('body').data('languages'));
52 | $('.content').imagesLoaded( function() {
53 | global.toc.calculateHeights();
54 | });
55 | });
56 | })(window);
57 |
58 |
--------------------------------------------------------------------------------
/docs/source/stylesheets/_icon-font.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'slate';
3 | src:font-url('slate.eot?-syv14m');
4 | src:font-url('slate.eot?#iefix-syv14m') format('embedded-opentype'),
5 | font-url('slate.woff2?-syv14m') format('woff2'),
6 | font-url('slate.woff?-syv14m') format('woff'),
7 | font-url('slate.ttf?-syv14m') format('truetype'),
8 | font-url('slate.svg?-syv14m#slate') format('svg');
9 | font-weight: normal;
10 | font-style: normal;
11 | }
12 |
13 | %icon {
14 | font-family: 'slate';
15 | speak: none;
16 | font-style: normal;
17 | font-weight: normal;
18 | font-variant: normal;
19 | text-transform: none;
20 | line-height: 1;
21 | }
22 |
23 | %icon-exclamation-sign {
24 | @extend %icon;
25 | content: "\e600";
26 | }
27 | %icon-info-sign {
28 | @extend %icon;
29 | content: "\e602";
30 | }
31 | %icon-ok-sign {
32 | @extend %icon;
33 | content: "\e606";
34 | }
35 | %icon-search {
36 | @extend %icon;
37 | content: "\e607";
38 | }
39 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/tasks/auto_annotate_models.rake:
--------------------------------------------------------------------------------
1 | # NOTE: only doing this in development as some production environments (Heroku)
2 | # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
3 | # NOTE: to have a dev-mode tool do its thing in production.
4 | if Rails.env.development?
5 | task :set_annotation_options do
6 | # You can override any of these by setting an environment variable of the
7 | # same name.
8 | Annotate.set_defaults({
9 | 'position_in_routes' => "before",
10 | 'position_in_class' => "before",
11 | 'position_in_test' => "before",
12 | 'position_in_fixture' => "before",
13 | 'position_in_factory' => "before",
14 | 'show_indexes' => "true",
15 | 'simple_indexes' => "false",
16 | 'model_dir' => "app/models",
17 | 'include_version' => "false",
18 | 'require' => "",
19 | 'exclude_tests' => "false",
20 | 'exclude_fixtures' => "false",
21 | 'exclude_factories' => "false",
22 | 'exclude_serializers' => 'true',
23 | 'ignore_model_sub_dir' => "false",
24 | 'skip_on_db_migrate' => "false",
25 | 'format_bare' => "true",
26 | 'format_rdoc' => "false",
27 | 'format_markdown' => "false",
28 | 'sort' => "false",
29 | 'classified_sort' => "true",
30 | 'force' => "true",
31 | 'trace' => "false",
32 | })
33 | end
34 |
35 | Annotate.load_tasks
36 | end
37 |
38 |
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/log/.keep
--------------------------------------------------------------------------------
/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/api/v1/docs/fonts/slate.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/fonts/slate.eot
--------------------------------------------------------------------------------
/public/api/v1/docs/fonts/slate.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Generated by IcoMoon
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/public/api/v1/docs/fonts/slate.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/fonts/slate.ttf
--------------------------------------------------------------------------------
/public/api/v1/docs/fonts/slate.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/fonts/slate.woff
--------------------------------------------------------------------------------
/public/api/v1/docs/fonts/slate.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/fonts/slate.woff2
--------------------------------------------------------------------------------
/public/api/v1/docs/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/images/logo.png
--------------------------------------------------------------------------------
/public/api/v1/docs/images/navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/api/v1/docs/images/navbar.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/spec/apis/resource/feeds/show_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FeedsController, '#show', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 |
9 | get api_v1_user_feed_path(user.id), format: :json
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | user = create_and_sign_in_user
19 | 5.times.collect{ FactoryGirl.create(:user) }.each do |u|
20 | 5.times{ FactoryGirl.create(:micropost, user: u) }
21 | FactoryGirl.create(:relationship, follower: u, followed: user)
22 | end
23 |
24 | get api_v1_microposts_path, format: :json
25 | end
26 |
27 | it_returns_status(200)
28 | it_follows_json_schema('regular/microposts')
29 | it_returns_collection_size(resource: 'microposts', size: 5*5)
30 | it_returns_collection_attribute_values(
31 | resource: 'microposts', model: proc{Micropost.first!}, attrs: [
32 | :id, :content, :user_id, :created_at, :updated_at
33 | ],
34 | modifiers: {
35 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
36 | id: proc{|i| i.to_s}
37 | }
38 | )
39 | end
40 |
41 | context 'when authenticated as an admin' do
42 | before do
43 | create_and_sign_in_admin_user
44 | user = FactoryGirl.create(:user)
45 | 5.times.collect{ FactoryGirl.create(:user) }.each do |u|
46 | 5.times{ FactoryGirl.create(:micropost, user: u) }
47 | FactoryGirl.create(:relationship, follower: u, followed: user)
48 | end
49 |
50 | get api_v1_microposts_path, format: :json
51 | end
52 |
53 | it_returns_status(200)
54 | it_follows_json_schema('admin/microposts')
55 | it_returns_collection_size(resource: 'microposts', size: 5*5)
56 | it_returns_collection_attribute_values(
57 | resource: 'microposts', model: proc{Micropost.first!}, attrs: [
58 | :id, :content, :user_id, :created_at, :updated_at
59 | ],
60 | modifiers: {
61 | [:created_at, :updated_at] => proc{|i| i.iso8601},
62 | id: proc{|i| i.to_s}
63 | }
64 | )
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/spec/apis/resource/followers/destroy_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FollowersController, '#destroy', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | 5.times{ FactoryGirl.create(:relationship, followed: user) }
9 |
10 | delete api_v1_user_follower_path(
11 | user_id: user.id, id: user.followers.first!.id
12 | )
13 | end
14 |
15 | it_returns_status(401)
16 | it_follows_json_schema('errors')
17 | end
18 |
19 | context 'when authenticated as not the owner' do
20 | before do
21 | user = FactoryGirl.create(:user)
22 | 5.times{ FactoryGirl.create(:relationship, followed: user) }
23 | create_and_sign_in_user
24 |
25 | @follower = user.followers.first!
26 |
27 | delete api_v1_user_follower_path(
28 | user_id: user.id, id: @follower.id
29 | )
30 | end
31 |
32 | it_returns_status(403)
33 | it_follows_json_schema('errors')
34 | end
35 |
36 | context 'when autenticated as the owner' do
37 | before do
38 | user = create_and_sign_in_user
39 | 5.times{ FactoryGirl.create(:relationship, followed: user) }
40 |
41 | @follower = user.followers.first!
42 |
43 | delete api_v1_user_follower_path(
44 | user_id: user.id, id: @follower.id
45 | )
46 | end
47 |
48 | it_returns_status(200)
49 |
50 | it_returns_attribute_values(
51 | resource: 'user', model: proc{@follower}, attrs: [
52 | :id, :name, :created_at, :microposts_count, :followers_count,
53 | :followings_count
54 | ],
55 | modifiers: {
56 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
57 | id: proc{|i| i.to_s},
58 | followings_count: proc{|i| i - 1}
59 | }
60 | )
61 | end
62 | end
63 | end
64 |
65 |
--------------------------------------------------------------------------------
/spec/apis/resource/followers/index_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FollowersController, '#index', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | 5.times{ FactoryGirl.create(:relationship, followed: user) }
9 |
10 | get api_v1_user_followers_path(user_id: user.id)
11 | end
12 |
13 | it_returns_status(401)
14 | it_follows_json_schema('errors')
15 | end
16 |
17 | context 'when authenticated as a regular user' do
18 | before do
19 | @user = FactoryGirl.create(:user)
20 | 5.times{ FactoryGirl.create(:relationship, followed: @user) }
21 | create_and_sign_in_user
22 |
23 | get api_v1_user_followers_path(user_id: @user.id)
24 | end
25 |
26 | it_returns_status(200)
27 | it_follows_json_schema('regular/users')
28 | it_returns_collection_size(resource: 'users', size: 5)
29 |
30 | it_returns_collection_attribute_values(
31 | resource: 'users', model: proc{@user.followers.first!}, attrs: [
32 | :id, :name, :created_at, :microposts_count, :followers_count,
33 | :followings_count
34 | ],
35 | modifiers: {
36 | [:created_at] => proc{|i| i.iso8601},
37 | id: proc{|i| i.to_s}
38 | }
39 | )
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/apis/resource/followings/create_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FollowingsController, '#create', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | following = FactoryGirl.create(:user)
9 |
10 | post api_v1_user_following_path(
11 | user_id: user.id, id: following.id
12 | )
13 | end
14 |
15 | it_returns_status(401)
16 | it_follows_json_schema('errors')
17 | end
18 |
19 | context 'when authenticated as not the owner' do
20 | before do
21 | user = FactoryGirl.create(:user)
22 | following = FactoryGirl.create(:user)
23 | create_and_sign_in_user
24 |
25 | post api_v1_user_following_path(
26 | user_id: user.id, id: following.id
27 | )
28 | end
29 |
30 | it_returns_status(403)
31 | it_follows_json_schema('errors')
32 | end
33 |
34 | context 'when authenticated as the owner' do
35 | before do
36 | user = FactoryGirl.create(:user)
37 | @following = FactoryGirl.create(:user)
38 | sign_in(user)
39 |
40 | post api_v1_user_following_path(
41 | user_id: user.id, id: @following.id
42 | )
43 | end
44 |
45 | it_returns_status(200)
46 | it_follows_json_schema('regular/user')
47 |
48 | it_returns_attribute_values(
49 | resource: 'user', model: proc{@following}, attrs: [
50 | :id, :name, :created_at, :microposts_count, :followers_count,
51 | :followings_count
52 | ],
53 | modifiers: {
54 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
55 | id: proc{|i| i.to_s},
56 | followers_count: proc{|i| i + 1}
57 | }
58 | )
59 | end
60 | end
61 | end
62 |
63 |
--------------------------------------------------------------------------------
/spec/apis/resource/followings/destroy_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FollowingsController, '#destroy', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | 5.times{ FactoryGirl.create(:relationship, follower: user) }
9 |
10 | delete api_v1_user_following_path(
11 | user_id: user.id, id: user.following.first!.id
12 | )
13 | end
14 |
15 | it_returns_status(401)
16 | it_follows_json_schema('errors')
17 | end
18 |
19 | context 'when authenticated as not the owner' do
20 | before do
21 | user = FactoryGirl.create(:user)
22 | 5.times{ FactoryGirl.create(:relationship, follower: user) }
23 | create_and_sign_in_user
24 | @following = user.following.first!
25 |
26 | delete api_v1_user_following_path(
27 | user_id: user.id, id: @following.id
28 | )
29 | end
30 |
31 | it_returns_status(403)
32 | it_follows_json_schema('errors')
33 | end
34 |
35 | context 'when authenticated as the owner' do
36 | before do
37 | user = FactoryGirl.create(:user)
38 | 5.times{ FactoryGirl.create(:relationship, follower: user) }
39 | sign_in(user)
40 | @following = user.following.first!
41 |
42 | delete api_v1_user_following_path(
43 | user_id: user.id, id: @following.id
44 | )
45 | end
46 |
47 | it_returns_status(200)
48 | it_follows_json_schema('regular/user')
49 | it_returns_attribute_values(
50 | resource: 'user', model: proc{@following}, attrs: [
51 | :id, :name, :created_at, :microposts_count, :followers_count,
52 | :followings_count
53 | ],
54 | modifiers: {
55 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
56 | id: proc{|i| i.to_s},
57 | followers_count: proc{|i| i - 1}
58 | }
59 | )
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/spec/apis/resource/followings/index_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::FollowingsController, '#index', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | 5.times{ FactoryGirl.create(:relationship, follower: user) }
9 |
10 | get api_v1_user_followings_path(user_id: user.id)
11 | end
12 |
13 | it_returns_status(401)
14 | it_follows_json_schema('errors')
15 | end
16 |
17 | context 'when authenticated as a regular user' do
18 | before do
19 | @user = FactoryGirl.create(:user)
20 | 5.times{ FactoryGirl.create(:relationship, follower: @user) }
21 | create_and_sign_in_user
22 |
23 | get api_v1_user_followings_path(user_id: @user.id)
24 | end
25 |
26 | it_returns_status(200)
27 | it_follows_json_schema('regular/users')
28 | it_returns_collection_size(resource: 'users', size: 5)
29 |
30 | it_returns_collection_attribute_values(
31 | resource: 'users', model: proc{@user.following.first!}, attrs: [
32 | :id, :name, :created_at, :microposts_count, :followers_count,
33 | :followings_count
34 | ],
35 | modifiers: {
36 | [:created_at] => proc{|i| i.iso8601},
37 | id: proc{|i| i.to_s}
38 | }
39 | )
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/apis/resource/microposts/create_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::MicropostsController, '#create', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.create(:user)
8 | micropost = FactoryGirl.attributes_for(:micropost).merge(user_id: user.id)
9 |
10 | post api_v1_microposts_path, jsonapi_style(micropost: micropost.as_json)
11 | end
12 |
13 | it_returns_status(401)
14 | it_follows_json_schema('errors')
15 | end
16 |
17 | context 'when authenticated as a regular user' do
18 | before do
19 | user = create_and_sign_in_user
20 | @micropost = FactoryGirl.attributes_for(:micropost).merge(user_id: user.id)
21 |
22 | post api_v1_microposts_path, jsonapi_style(micropost: @micropost.as_json)
23 | end
24 |
25 | it_returns_status(201)
26 | it_follows_json_schema('regular/micropost')
27 |
28 | it_returns_attribute_values(
29 | resource: 'micropost', model: proc{@micropost}, attrs: [
30 | :content, :user_id
31 | ]
32 | )
33 | end
34 |
35 | context 'when authenticated as an admin' do
36 | before do
37 | user = create_and_sign_in_admin
38 | @micropost = FactoryGirl.attributes_for(:micropost).merge(user_id: user.id)
39 |
40 | post api_v1_microposts_path, jsonapi_style(micropost: @micropost.as_json)
41 | end
42 |
43 | it_returns_status(201)
44 | it_follows_json_schema('admin/micropost')
45 |
46 | it_returns_attribute_values(
47 | resource: 'micropost', model: proc{@micropost}, attrs: [
48 | :content, :user_id
49 | ]
50 | )
51 | end
52 | end
53 | end
54 |
55 |
56 |
--------------------------------------------------------------------------------
/spec/apis/resource/microposts/destroy_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::MicropostsController, '#destroy', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | micropost = FactoryGirl.create(:micropost)
8 |
9 | delete api_v1_micropost_path(micropost), format: :json
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | @micropost = FactoryGirl.create(:micropost)
20 |
21 | delete api_v1_micropost_path(@micropost), format: :json
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/micropost')
26 | it_returns_attribute_values(
27 | resource: 'micropost', model: proc{@micropost}, attrs: [
28 | :id, :content, :user_id, :created_at, :updated_at
29 | ],
30 | modifiers: {
31 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
32 | id: proc{|i| i.to_s}
33 | }
34 | )
35 | end
36 |
37 | context 'when authenticated as an admin' do
38 | before do
39 | create_and_sign_in_admin
40 | @micropost = FactoryGirl.create(:micropost)
41 |
42 | delete api_v1_micropost_path(@micropost), format: :json
43 | end
44 |
45 | it_returns_status(200)
46 | it_follows_json_schema('admin/micropost')
47 | it_returns_attribute_values(
48 | resource: 'micropost', model: proc{@micropost}, attrs: [
49 | :id, :content, :user_id, :created_at, :updated_at
50 | ],
51 | modifiers: {
52 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
53 | id: proc{|i| i.to_s}
54 | }
55 | )
56 | end
57 | end
58 | end
59 |
60 |
--------------------------------------------------------------------------------
/spec/apis/resource/microposts/index_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::MicropostsController, '#index', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | 5.times{ FactoryGirl.create(:micropost) }
8 |
9 | get api_v1_microposts_path, format: :json
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | 5.times{ FactoryGirl.create(:micropost) }
20 |
21 | get api_v1_microposts_path, format: :json
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/microposts')
26 | it_returns_collection_size(resource: 'microposts', size: 5)
27 | it_returns_collection_attribute_values(
28 | resource: 'microposts', model: proc{Micropost.first!}, attrs: [
29 | :id, :content, :user_id, :created_at, :updated_at
30 | ],
31 | modifiers: {
32 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
33 | id: proc{|i| i.to_s}
34 | }
35 | )
36 | end
37 |
38 | context 'when authenticated as an admin' do
39 | before do
40 | create_and_sign_in_admin_user
41 | 5.times{ FactoryGirl.create(:micropost) }
42 |
43 | get api_v1_microposts_path, format: :json
44 | end
45 |
46 | it_returns_status(200)
47 | it_follows_json_schema('admin/microposts')
48 | it_returns_collection_size(resource: 'microposts', size: 5)
49 | it_returns_collection_attribute_values(
50 | resource: 'microposts', model: proc{Micropost.first!}, attrs: [
51 | :id, :content, :user_id, :created_at, :updated_at
52 | ],
53 | modifiers: {
54 | [:created_at, :updated_at] => proc{|i| i.iso8601},
55 | id: proc{|i| i.to_s}
56 | }
57 | )
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/spec/apis/resource/microposts/show_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::MicropostsController, '#show', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | micropost = FactoryGirl.create(:micropost)
8 |
9 | get api_v1_micropost_path(micropost), format: :json
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | @micropost = FactoryGirl.create(:micropost)
20 |
21 | get api_v1_micropost_path(@micropost), format: :json
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/micropost')
26 |
27 | it_returns_attribute_values(
28 | resource: 'micropost', model: proc{@micropost}, attrs: [
29 | :id, :content, :user_id, :created_at, :updated_at
30 | ],
31 | modifiers: {
32 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
33 | id: proc{|i| i.to_s}
34 | }
35 | )
36 | end
37 |
38 | context 'when authenticated as an admin' do
39 | before do
40 | create_and_sign_in_admin
41 | @micropost = FactoryGirl.create(:micropost)
42 |
43 | get api_v1_micropost_path(@micropost), format: :json
44 | end
45 |
46 | it_returns_status(200)
47 | it_follows_json_schema('admin/micropost')
48 |
49 | it_returns_attribute_values(
50 | resource: 'micropost', model: proc{@micropost}, attrs: [
51 | :id, :content, :user_id, :created_at, :updated_at
52 | ],
53 | modifiers: {
54 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
55 | id: proc{|i| i.to_s}
56 | }
57 | )
58 | end
59 | end
60 | end
61 |
62 |
--------------------------------------------------------------------------------
/spec/apis/resource/microposts/update_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::MicropostsController, '#update', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | micropost = FactoryGirl.create(:micropost)
8 |
9 | put api_v1_micropost_path(micropost), format: :json
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | @micropost = FactoryGirl.create(:micropost)
20 |
21 | put api_v1_micropost_path(@micropost), format: :json
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/micropost')
26 | it_returns_attribute_values(
27 | resource: 'micropost', model: proc{@micropost}, attrs: [
28 | :id, :content, :user_id, :created_at, :updated_at
29 | ],
30 | modifiers: {
31 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
32 | id: proc{|i| i.to_s}
33 | }
34 | )
35 | end
36 |
37 | context 'when authenticated as an admin' do
38 | before do
39 | create_and_sign_in_admin
40 | @micropost = FactoryGirl.create(:micropost)
41 |
42 | put api_v1_micropost_path(@micropost), format: :json
43 | end
44 |
45 | it_returns_status(200)
46 | it_follows_json_schema('admin/micropost')
47 | it_returns_attribute_values(
48 | resource: 'micropost', model: proc{@micropost}, attrs: [
49 | :id, :content, :user_id, :created_at, :updated_at
50 | ],
51 | modifiers: {
52 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
53 | id: proc{|i| i.to_s}
54 | }
55 | )
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/spec/apis/resource/sessions/create_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::SessionsController, '#create', type: :api do
4 | describe 'Authoriation' do
5 | context 'with wrong params' do
6 | before do
7 | user = FactoryGirl.create(:user, {
8 | password: 'foobar', password_confirmation: nil
9 | })
10 |
11 | post api_v1_sessions_path(
12 | jsonapi_style(user: {email: user.email, password: 'foobar1'})
13 | )
14 | end
15 |
16 | it_returns_status(401)
17 | end
18 |
19 | context 'with correct params' do
20 | before do
21 | user = FactoryGirl.create(:user, {
22 | password: 'foobar', password_confirmation: nil
23 | })
24 |
25 | post api_v1_sessions_path(
26 | jsonapi_style(user: {email: user.email, password: 'foobar'})
27 | )
28 | end
29 |
30 | it_returns_status(201)
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/spec/apis/resource/sessions/show_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::SessionsController, '#show', type: :api do
4 | describe 'Authoriation' do
5 | context 'with wrong params' do
6 | before do
7 | user = FactoryGirl.create(:user, {
8 | password: 'foobar', password_confirmation: 'foobar'
9 | })
10 |
11 | get api_v1_session_path(user.id)
12 |
13 | end
14 |
15 | it_returns_status(401)
16 | it_follows_json_schema('errors')
17 | end
18 |
19 | context 'with correct params' do
20 | before do
21 | user = FactoryGirl.create(:user, {
22 | password: 'foobar', password_confirmation: 'foobar'
23 | })
24 | sign_in(user)
25 |
26 | get api_v1_session_path(user.id)
27 | end
28 |
29 | it_returns_status(200)
30 | it_follows_json_schema('regular/session')
31 | end
32 | end
33 | end
34 |
35 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/activate_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, '#activate', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | context 'with correct token' do
7 | before do
8 | @user = FactoryGirl.create(:user)
9 |
10 | post activate_api_v1_users_path(email: @user.email, token: @user.activation_token)
11 | end
12 |
13 | it_returns_status(200)
14 | it_follows_json_schema('regular/user')
15 | it_returns_attribute_values(
16 | resource: 'user', model: proc{@user}, attrs: [
17 | :name, :email
18 | ]
19 | )
20 | end
21 |
22 | context 'with wrong token' do
23 | before do
24 | @user = FactoryGirl.create(:user)
25 |
26 | post activate_api_v1_users_path(email: @user.email, token: 'allo?')
27 | end
28 |
29 | it_returns_status(404)
30 | it_follows_json_schema('errors')
31 | end
32 | end
33 |
34 | context 'when authenticated as a regular user' do
35 | before do
36 | create_and_sign_in_user
37 | @user = FactoryGirl.create(:user)
38 |
39 | post activate_api_v1_users_path(email: @user.email, token: @user.activation_token)
40 | end
41 |
42 | it_returns_status(200)
43 | it_follows_json_schema('regular/user')
44 | it_returns_attribute_values(
45 | resource: 'user', model: proc{@user}, attrs: [
46 | :name, :email
47 | ]
48 | )
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/create_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, '#create', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | user = FactoryGirl.attributes_for(:user)
8 | post api_v1_users_path, jsonapi_style(user: user.as_json)
9 | end
10 |
11 | it_returns_status(201)
12 | it_follows_json_schema('regular/user')
13 | end
14 |
15 | context 'when authenticated as a regular user' do
16 | before do
17 | create_and_sign_in_user
18 | @user = FactoryGirl.attributes_for(:user)
19 |
20 | post api_v1_users_path, jsonapi_style(user: @user.as_json)
21 | end
22 |
23 | it_returns_status(201)
24 | it_follows_json_schema('regular/user')
25 | it_returns_attribute_values(
26 | resource: 'user', model: proc{@user}, attrs: [
27 | :name, :email
28 | ]
29 | )
30 | end
31 |
32 | context 'when authenticated as an admin' do
33 | before do
34 | create_and_sign_in_admin
35 | @user = FactoryGirl.attributes_for(:user)
36 |
37 | post api_v1_users_path, jsonapi_style(user: @user.as_json)
38 | end
39 |
40 | it_returns_status(201)
41 | it_follows_json_schema('regular/user')
42 | it_returns_attribute_values(
43 | resource: 'user', model: proc{@user}, attrs: [
44 | :name, :email
45 | ]
46 | )
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/destroy_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, type: :api do
4 | context :destroy do
5 | context 'when authenticated as a guest' do
6 | before do
7 | @user = FactoryGirl.create(:user)
8 |
9 | delete api_v1_user_path(@user.id)
10 | end
11 |
12 | it_returns_status(401)
13 | it_follows_json_schema('errors')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | @user = FactoryGirl.create(:user)
20 |
21 | delete api_v1_user_path(@user.id)
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/user')
26 | it_returns_attribute_values(
27 | resource: 'user', model: proc{@user}, attrs: [
28 | :id, :name, :email, :created_at
29 | ], modifiers: {
30 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
31 | id: proc{|i| i.to_s}
32 | }
33 | )
34 | end
35 |
36 | context 'when authenticated as an admin' do
37 | before do
38 | create_and_sign_in_admin
39 | @user = FactoryGirl.create(:user)
40 |
41 | delete api_v1_user_path(@user.id)
42 | end
43 |
44 | it_returns_status(200)
45 | it_follows_json_schema('admin/user')
46 | it_returns_attribute_values(
47 | resource: 'user', model: proc{@user}, attrs: User.column_names,
48 | modifiers: {
49 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
50 | id: proc{|i| i.to_s}
51 | }
52 | )
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/index_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, '#index', type: :api do
4 | describe 'Authorization' do
5 | context 'when not authenticated' do
6 | before do
7 | 5.times{ FactoryGirl.create(:user) }
8 |
9 | get api_v1_users_path, format: :json
10 | end
11 |
12 | it_returns_status(200)
13 | it_follows_json_schema('guest/users')
14 | end
15 |
16 | context 'when authenticated as a regular user' do
17 | before do
18 | create_and_sign_in_user
19 | 5.times{ FactoryGirl.create(:user) }
20 |
21 | get api_v1_users_path, format: :json
22 | end
23 |
24 | it_returns_status(200)
25 | it_follows_json_schema('regular/users')
26 | it_returns_collection_size(resource: 'users', size: 5+1)
27 |
28 | it_returns_collection_attribute_values(
29 | resource: 'users', model: proc{User.first!}, attrs: [
30 | :id, :name, :created_at, :microposts_count, :followers_count,
31 | :followings_count
32 | ],
33 | modifiers: {
34 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
35 | id: proc{|i| i.to_s}
36 | }
37 | )
38 | end
39 |
40 | context 'when authenticated as an admin' do
41 | before do
42 | create_and_sign_in_admin_user
43 | 5.times{ FactoryGirl.create(:user) }
44 |
45 | get api_v1_users_path, format: :json
46 | end
47 |
48 | it_returns_status(200)
49 | it_follows_json_schema('admin/users')
50 | it_returns_collection_size(resource: 'users', size: 5+1)
51 |
52 | it_returns_collection_attribute_values(
53 | resource: 'users', model: proc{User.first!}, attrs: User.column_names,
54 | modifiers: {
55 | [:created_at, :updated_at] => proc{|i| i.iso8601},
56 | id: proc{|i| i.to_s}
57 | }
58 | )
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/show_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, '#show', type: :api do
4 | describe 'Authorization' do
5 | context 'when as guest' do
6 | before do
7 | FactoryGirl.create(:user)
8 | @user = User.last!
9 |
10 | get api_v1_user_path(@user.id)
11 | end
12 |
13 | it_returns_status(200)
14 | it_follows_json_schema('guest/user')
15 | it_returns_attribute_values(
16 | resource: 'user', model: proc{@user}, attrs: [:name, :created_at],
17 | modifiers: {
18 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
19 | }
20 | )
21 | end
22 |
23 | context 'when authenticated as a regular user' do
24 | before do
25 | create_and_sign_in_user
26 | FactoryGirl.create(:user)
27 | @user = User.last!
28 |
29 | get api_v1_user_path(@user.id)
30 | end
31 |
32 | it_returns_status(200)
33 | it_follows_json_schema('regular/user')
34 | it_returns_attribute_values(
35 | resource: 'user', model: proc{@user}, attrs: [
36 | :id, :name, :created_at, :microposts_count, :followers_count,
37 | :followings_count
38 | ],
39 | modifiers: {
40 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
41 | id: proc{|i| i.to_s}
42 | }
43 | )
44 | end
45 |
46 | context 'when authenticated as an admin' do
47 | before do
48 | create_and_sign_in_admin
49 | FactoryGirl.create(:user)
50 | @user = User.last!
51 |
52 | get api_v1_user_path(@user.id)
53 | end
54 |
55 | it_returns_status(200)
56 | it_follows_json_schema('admin/user')
57 | it_returns_attribute_values(
58 | resource: 'user', model: proc{@user}, attrs: User.column_names,
59 | modifiers: {
60 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
61 | id: proc{|i| i.to_s}
62 | }
63 | )
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/spec/apis/resource/users/update_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Api::V1::UsersController, '#update', type: :api do
4 | describe 'Authorization' do
5 | context 'when authenticated as a guest user' do
6 | before do
7 | FactoryGirl.create(:user)
8 | @user = User.last!
9 | @user.name = 'Something else'
10 |
11 | put api_v1_user_path(@user.id), jsonapi_style(user: @user.as_json)
12 | end
13 |
14 | it_returns_status(401)
15 | it_follows_json_schema('errors')
16 | end
17 |
18 | context 'when authenticated as a regular user' do
19 | before do
20 | create_and_sign_in_user
21 | FactoryGirl.create(:user)
22 | @user = User.last!
23 | @user.name = 'Something else'
24 |
25 | put api_v1_user_path(@user.id), jsonapi_style(user: @user.as_json)
26 | end
27 |
28 | it_returns_status(200)
29 | it_follows_json_schema('regular/user')
30 | it_returns_attribute_values(
31 | resource: 'user', model: proc{@user}, attrs: [
32 | :id, :name, :created_at, :microposts_count, :followers_count,
33 | :followings_count
34 | ],
35 | modifiers: {
36 | created_at: proc{|i| i.in_time_zone('UTC').iso8601.to_s},
37 | id: proc{|i| i.to_s}
38 | }
39 | )
40 | end
41 |
42 | context 'when authenticated as an admin' do
43 | before do
44 | create_and_sign_in_admin
45 | FactoryGirl.create(:user)
46 | @user = User.last!
47 | @user.name = 'Something else'
48 |
49 | put api_v1_user_path(@user.id), jsonapi_style(user: @user.as_json)
50 | end
51 |
52 | it_returns_status(200)
53 | it_follows_json_schema('admin/user')
54 | it_returns_attribute_values(
55 | resource: 'user', model: proc{@user}, attrs: User.column_names,
56 | modifiers: {
57 | [:created_at, :updated_at] => proc{|i| i.in_time_zone('UTC').iso8601.to_s},
58 | id: proc{|i| i.to_s}
59 | }
60 | )
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/spec/factories/micropost.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :micropost do
3 | content { 'foobar' }
4 |
5 | user
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/relationships.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: relationships
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # followed_id :integer
9 | # follower_id :integer
10 | #
11 | # Indexes
12 | #
13 | # index_relationships_on_followed_id (followed_id)
14 | # index_relationships_on_follower_id (follower_id)
15 | # index_relationships_on_follower_id_and_followed_id (follower_id,followed_id) UNIQUE
16 | #
17 |
18 | FactoryGirl.define do
19 | factory :relationship do
20 | association :follower, factory: :user
21 | association :followed, factory: :user
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # activated :boolean default(FALSE)
7 | # activated_at :datetime
8 | # activation_digest :string
9 | # admin :boolean default(FALSE)
10 | # email :string
11 | # followers_count :integer default(0), not null
12 | # followings_count :integer default(0), not null
13 | # microposts_count :integer default(0), not null
14 | # name :string
15 | # password_digest :string
16 | # remember_digest :string
17 | # reset_digest :string
18 | # reset_sent_at :datetime
19 | # token :string not null
20 | # created_at :datetime not null
21 | # updated_at :datetime not null
22 | #
23 | # Indexes
24 | #
25 | # index_users_on_email (email) UNIQUE
26 | #
27 |
28 | FactoryGirl.define do
29 | factory :user do
30 | pwd = Faker::Internet.password
31 |
32 | email { Faker::Internet.email }
33 | name { Faker::Name.name }
34 | password { pwd }
35 | password_confirmation { pwd }
36 |
37 | factory :admin do
38 | admin { true }
39 | end
40 | =begin
41 | factory :user_with_microposts do
42 | transient do
43 | posts_count 5
44 | end
45 |
46 | after(:create) do |user, evaluator|
47 | create_list(:micropost, evaluator.posts_count, user: user)
48 | end
49 | end
50 | =end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require File.expand_path('../../config/environment', __FILE__)
3 | abort("The Rails environment is running in production mode!") if Rails.env.production?
4 | require 'spec_helper'
5 | require 'rspec/rails'
6 |
7 | require 'rspec/json_schema'
8 |
9 | Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
10 | ActiveRecord::Migration.maintain_test_schema!
11 |
12 | RSpec.configure do |config|
13 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
14 | config.use_transactional_fixtures = true
15 | config.infer_spec_type_from_file_location!
16 | config.filter_rails_from_backtrace!
17 | config.include Rspec::ApiHelpers.with(adapter: :json_api), type: :api #from rspec-api_helpers gem
18 | end
19 |
--------------------------------------------------------------------------------
/spec/schemas/admin/micropost.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "properties": {
5 | "data": {
6 | "type": "object",
7 | "properties": {
8 | "id": {
9 | "type": "string"
10 | },
11 | "type": {
12 | "type": "string"
13 | },
14 | "attributes": {
15 | "type": "object",
16 | "properties": {
17 | "content": {
18 | "type": "string"
19 | },
20 | "user-id": {
21 | "type": "integer"
22 | },
23 | "created-at": {
24 | "type": "string"
25 | },
26 | "updated-at": {
27 | "type": "string"
28 | }
29 | },
30 | "required": [
31 | "content",
32 | "user-id",
33 | "created-at",
34 | "updated-at"
35 | ]
36 | },
37 | "relationships": {
38 | "type": "object",
39 | "properties": {
40 | "user": {
41 | "type": "object",
42 | "properties": {
43 | "links": {
44 | "type": "object",
45 | "properties": {
46 | "related": {
47 | "type": "string"
48 | }
49 | },
50 | "required": [
51 | "related"
52 | ]
53 | }
54 | },
55 | "required": [
56 | "links"
57 | ]
58 | }
59 | },
60 | "required": [
61 | "user"
62 | ]
63 | }
64 | },
65 | "required": [
66 | "id",
67 | "type",
68 | "attributes",
69 | "relationships"
70 | ]
71 | }
72 | },
73 | "required": [
74 | "data"
75 | ]
76 | }
77 |
--------------------------------------------------------------------------------
/spec/schemas/errors.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "properties": {
5 | "errors": {
6 | "type": "array",
7 | "items": {
8 | "type": "object",
9 | "properties": {
10 | "status": {
11 | "type": "integer"
12 | },
13 | "title": {
14 | "type": "string"
15 | },
16 | "detail": {
17 | "type": "string"
18 | },
19 | "source": {
20 | "type": "object",
21 | "properties": {
22 | "pointer": {
23 | "type": "string"
24 | }
25 | },
26 | "required": [
27 | "pointer"
28 | ]
29 | }
30 | },
31 | "required": [
32 | "status",
33 | "title",
34 | "detail",
35 | "source"
36 | ]
37 | }
38 | }
39 | },
40 | "required": [
41 | "errors"
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/spec/schemas/regular/micropost.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "properties": {
5 | "data": {
6 | "type": "object",
7 | "properties": {
8 | "id": {
9 | "type": "string"
10 | },
11 | "type": {
12 | "type": "string"
13 | },
14 | "attributes": {
15 | "type": "object",
16 | "properties": {
17 | "content": {
18 | "type": "string"
19 | },
20 | "user-id": {
21 | "type": "integer"
22 | },
23 | "created-at": {
24 | "type": "string"
25 | }
26 | },
27 | "required": [
28 | "content",
29 | "user-id",
30 | "created-at",
31 | "updated-at"
32 | ]
33 | },
34 | "relationships": {
35 | "type": "object",
36 | "properties": {
37 | "user": {
38 | "type": "object",
39 | "properties": {
40 | "links": {
41 | "type": "object",
42 | "properties": {
43 | "related": {
44 | "type": "string"
45 | }
46 | },
47 | "required": [
48 | "related"
49 | ]
50 | }
51 | },
52 | "required": [
53 | "links"
54 | ]
55 | }
56 | },
57 | "required": [
58 | "user"
59 | ]
60 | }
61 | },
62 | "required": [
63 | "id",
64 | "type",
65 | "attributes",
66 | "relationships"
67 | ]
68 | }
69 | },
70 | "required": [
71 | "data"
72 | ]
73 | }
74 |
--------------------------------------------------------------------------------
/spec/schemas/regular/microposts.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "properties": {
5 | "data": {
6 | "type": "array",
7 | "items": {
8 | "type": "object",
9 | "properties": {
10 | "id": {
11 | "type": "string"
12 | },
13 | "type": {
14 | "type": "string"
15 | },
16 | "attributes": {
17 | "type": "object",
18 | "properties": {
19 | "content": {
20 | "type": "string"
21 | },
22 | "user-id": {
23 | "type": "integer"
24 | },
25 | "created-at": {
26 | "type": "string"
27 | }
28 | },
29 | "required": [
30 | "content",
31 | "user-id",
32 | "created-at"
33 | ]
34 | },
35 | "relationships": {
36 | "type": "object",
37 | "properties": {
38 | "user": {
39 | "type": "object",
40 | "properties": {
41 | "links": {
42 | "type": "object",
43 | "properties": {
44 | "related": {
45 | "type": "string"
46 | }
47 | },
48 | "required": [
49 | "related"
50 | ]
51 | }
52 | },
53 | "required": [
54 | "links"
55 | ]
56 | }
57 | },
58 | "required": [
59 | "user"
60 | ]
61 | }
62 | },
63 | "required": [
64 | "id",
65 | "type",
66 | "attributes",
67 | "relationships"
68 | ]
69 | }
70 | },
71 | "meta": {
72 | "type": "object",
73 | "properties": {
74 | "current-page": {
75 | "type": "integer"
76 | },
77 | "next-page": {
78 | "type": ["null", "integer"]
79 | },
80 | "prev-page": {
81 | "type": ["null", "integer"]
82 | },
83 | "total-pages": {
84 | "type": "integer"
85 | },
86 | "total-count": {
87 | "type": "integer"
88 | }
89 | },
90 | "required": [
91 | "current-page",
92 | "next-page",
93 | "prev-page",
94 | "total-pages",
95 | "total-count"
96 | ]
97 | }
98 | },
99 | "required": [
100 | "data",
101 | "links",
102 | "meta"
103 | ]
104 | }
105 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.expect_with :rspec do |expectations|
3 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4 | end
5 |
6 | config.mock_with :rspec do |mocks|
7 | mocks.verify_partial_doubles = true
8 | end
9 |
10 | config.shared_context_metadata_behavior = :apply_to_host_groups
11 | end
12 |
--------------------------------------------------------------------------------
/spec/support/api_helpers.rb:
--------------------------------------------------------------------------------
1 | module ApiHelpers
2 | def jsonapi_style(hash)
3 | resource_key = hash.first.first
4 | resource_attributes = hash.first.last
5 |
6 | return {
7 | data: {
8 | type: resource_key.to_s.pluralize,
9 | attributes: resource_attributes
10 | }
11 | }
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.include ApiHelpers, type: :api
17 | end
18 |
--------------------------------------------------------------------------------
/spec/support/authentication_helper.rb:
--------------------------------------------------------------------------------
1 | module AuthenticationHelper
2 | def sign_in(user)
3 | header('Authorization', %Q{Token token="#{user.token}", email="#{user.email}"})
4 | end
5 |
6 | def create_and_sign_in_user
7 | user = FactoryGirl.create(:user)
8 | sign_in(user)
9 | return user
10 | end
11 | alias_method :create_and_sign_in_another_user, :create_and_sign_in_user
12 |
13 | def create_and_sign_in_admin
14 | admin = FactoryGirl.create(:admin)
15 | sign_in(admin)
16 | return admin
17 | end
18 | alias_method :create_and_sign_in_admin_user, :create_and_sign_in_admin
19 | end
20 |
21 | RSpec.configure do |config|
22 | config.include AuthenticationHelper, :type=>:api
23 | end
24 |
--------------------------------------------------------------------------------
/spec/support/database_cleaner.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.before :suite do
3 | DatabaseCleaner[:active_record].strategy = :transaction
4 | DatabaseCleaner.clean_with(:truncation)
5 | end
6 |
7 | config.around(:each) do |example|
8 | DatabaseCleaner.cleaning do
9 | example.run
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/support/factory_girl.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include FactoryGirl::Syntax::Methods
3 |
4 | config.before(:suite) do
5 | begin
6 | DatabaseCleaner.start
7 | FactoryGirl.lint
8 | ensure
9 | DatabaseCleaner.clean
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/support/rack_helper.rb:
--------------------------------------------------------------------------------
1 | module RackHelper
2 | include Rack::Test::Methods
3 |
4 | def app
5 | Rails.application
6 | end
7 | end
8 |
9 | RSpec.configure do |config|
10 | config.include RackHelper, type: :api
11 | config.include Rails.application.routes.url_helpers, type: :api
12 | end
13 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/microposts_controller_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: microposts
4 | #
5 | # id :integer not null, primary key
6 | # content :text
7 | # picture :string
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | # user_id :integer
11 | #
12 | # Indexes
13 | #
14 | # index_microposts_on_user_id (user_id)
15 | #
16 |
17 | require 'test_helper'
18 |
19 | class MicropostsControllerTest < ActionDispatch::IntegrationTest
20 |
21 | def setup
22 | @micropost = microposts(:orange)
23 | end
24 |
25 | test "should redirect create when not logged in" do
26 | assert_no_difference 'Micropost.count' do
27 | post microposts_path, params: { micropost: { content: "Lorem ipsum" } }
28 | end
29 | assert_redirected_to login_url
30 | end
31 |
32 | test "should redirect destroy when not logged in" do
33 | assert_no_difference 'Micropost.count' do
34 | delete micropost_path(@micropost)
35 | end
36 | assert_redirected_to login_url
37 | end
38 |
39 | test "should redirect destroy for wrong micropost" do
40 | log_in_as(users(:michael))
41 | micropost = microposts(:ants)
42 | assert_no_difference 'Micropost.count' do
43 | delete micropost_path(micropost)
44 | end
45 | assert_redirected_to root_url
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/test/controllers/relationships_controller_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: relationships
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # followed_id :integer
9 | # follower_id :integer
10 | #
11 | # Indexes
12 | #
13 | # index_relationships_on_followed_id (followed_id)
14 | # index_relationships_on_follower_id (follower_id)
15 | # index_relationships_on_follower_id_and_followed_id (follower_id,followed_id) UNIQUE
16 | #
17 |
18 | require 'test_helper'
19 |
20 | class RelationshipsControllerTest < ActionDispatch::IntegrationTest
21 |
22 | test "create should require logged-in user" do
23 | assert_no_difference 'Relationship.count' do
24 | post relationships_path
25 | end
26 | assert_redirected_to login_url
27 | end
28 |
29 | test "destroy should require logged-in user" do
30 | assert_no_difference 'Relationship.count' do
31 | delete relationship_path(relationships(:one))
32 | end
33 | assert_redirected_to login_url
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/controllers/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionDispatch::IntegrationTest
4 |
5 | test "should get new" do
6 | get login_path
7 | assert_response :success
8 | end
9 | end
--------------------------------------------------------------------------------
/test/controllers/static_pages_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class StaticPagesControllerTest < ActionDispatch::IntegrationTest
4 |
5 | test "should get home" do
6 | get root_path
7 | assert_response :success
8 | assert_select "title", "Ruby on Rails Tutorial Sample App"
9 | end
10 |
11 | test "should get help" do
12 | get help_path
13 | assert_response :success
14 | assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
15 | end
16 |
17 | test "should get about" do
18 | get about_path
19 | assert_response :success
20 | assert_select "title", "About | Ruby on Rails Tutorial Sample App"
21 | end
22 |
23 | test "should get contact" do
24 | get contact_path
25 | assert_response :success
26 | assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/fixtures/microposts.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: microposts
4 | #
5 | # id :integer not null, primary key
6 | # content :text
7 | # picture :string
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | # user_id :integer
11 | #
12 | # Indexes
13 | #
14 | # index_microposts_on_user_id (user_id)
15 | #
16 |
17 | orange:
18 | content: "I just ate an orange!"
19 | created_at: <%= 10.minutes.ago %>
20 | user: michael
21 |
22 | tau_manifesto:
23 | content: "Check out the @tauday site by @mhartl: http://tauday.com"
24 | created_at: <%= 3.years.ago %>
25 | user: michael
26 |
27 | cat_video:
28 | content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
29 | created_at: <%= 2.hours.ago %>
30 | user: michael
31 |
32 | most_recent:
33 | content: "Writing a short test"
34 | created_at: <%= Time.zone.now %>
35 | user: michael
36 |
37 | <% 30.times do |n| %>
38 | micropost_<%= n %>:
39 | content: <%= Faker::Lorem.sentence(5) %>
40 | created_at: <%= 42.days.ago %>
41 | user: michael
42 | <% end %>
43 |
44 | ants:
45 | content: "Oh, is that what you want? Because that's how you get ants!"
46 | created_at: <%= 2.years.ago %>
47 | user: archer
48 |
49 | zone:
50 | content: "Danger zone!"
51 | created_at: <%= 3.days.ago %>
52 | user: archer
53 |
54 | tone:
55 | content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
56 | created_at: <%= 10.minutes.ago %>
57 | user: lana
58 |
59 | van:
60 | content: "Dude, this van's, like, rolling probable cause."
61 | created_at: <%= 4.hours.ago %>
62 | user: lana
63 |
--------------------------------------------------------------------------------
/test/fixtures/relationships.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: relationships
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # followed_id :integer
9 | # follower_id :integer
10 | #
11 | # Indexes
12 | #
13 | # index_relationships_on_followed_id (followed_id)
14 | # index_relationships_on_follower_id (follower_id)
15 | # index_relationships_on_follower_id_and_followed_id (follower_id,followed_id) UNIQUE
16 | #
17 |
18 | one:
19 | follower: michael
20 | followed: lana
21 |
22 | two:
23 | follower: michael
24 | followed: malory
25 |
26 | three:
27 | follower: lana
28 | followed: michael
29 |
30 | four:
31 | follower: archer
32 | followed: michael
33 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # activated :boolean default(FALSE)
7 | # activated_at :datetime
8 | # activation_digest :string
9 | # admin :boolean default(FALSE)
10 | # email :string
11 | # followers_count :integer default(0), not null
12 | # followings_count :integer default(0), not null
13 | # microposts_count :integer default(0), not null
14 | # name :string
15 | # password_digest :string
16 | # remember_digest :string
17 | # reset_digest :string
18 | # reset_sent_at :datetime
19 | # token :string not null
20 | # created_at :datetime not null
21 | # updated_at :datetime not null
22 | #
23 | # Indexes
24 | #
25 | # index_users_on_email (email) UNIQUE
26 | #
27 |
28 | michael:
29 | name: Michael Example
30 | email: michael@example.com
31 | password_digest: <%= User.digest('password') %>
32 | admin: true
33 | token: <%= SecureRandom.hex %>
34 | activated: true
35 | activated_at: <%= Time.zone.now %>
36 |
37 | archer:
38 | name: Sterling Archer
39 | email: duchess@example.gov
40 | password_digest: <%= User.digest('password') %>
41 | token: <%= SecureRandom.hex %>
42 | activated: true
43 | activated_at: <%= Time.zone.now %>
44 |
45 | lana:
46 | name: Lana Kane
47 | email: hands@example.gov
48 | password_digest: <%= User.digest('password') %>
49 | token: <%= SecureRandom.hex %>
50 | activated: true
51 | activated_at: <%= Time.zone.now %>
52 |
53 | malory:
54 | name: Malory Archer
55 | email: boss@example.gov
56 | password_digest: <%= User.digest('password') %>
57 | token: <%= SecureRandom.hex %>
58 | activated: true
59 | activated_at: <%= Time.zone.now %>
60 |
61 | <% 30.times do |n| %>
62 | user_<%= n %>:
63 | name: <%= "User #{n}" %>
64 | email: <%= "user-#{n}@example.com" %>
65 | password_digest: <%= User.digest('password') %>
66 | token: <%= SecureRandom.hex %>
67 | activated: true
68 | activated_at: <%= Time.zone.now %>
69 | <% end %>
70 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/helpers/.keep
--------------------------------------------------------------------------------
/test/helpers/sessions_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsHelperTest < ActionView::TestCase
4 |
5 | def setup
6 | @user = users(:michael)
7 | remember(@user)
8 | end
9 |
10 | test "current_user returns right user when session is nil" do
11 | assert_equal @user, current_user
12 | assert is_logged_in?
13 | end
14 |
15 | test "current_user returns nil when remember digest is wrong" do
16 | @user.update_attribute(:remember_digest, User.digest(User.new_token))
17 | assert_nil current_user
18 | end
19 | end
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/integration/.keep
--------------------------------------------------------------------------------
/test/integration/following_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class FollowingTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | @other = users(:archer)
8 | log_in_as(@user)
9 | end
10 |
11 | test "following page" do
12 | get following_user_path(@user)
13 | assert_not @user.following.empty?
14 | assert_match @user.following.count.to_s, response.body
15 | @user.following.each do |user|
16 | assert_select "a[href=?]", user_path(user)
17 | end
18 | end
19 |
20 | test "followers page" do
21 | get followers_user_path(@user)
22 | assert_not @user.followers.empty?
23 | assert_match @user.followers.count.to_s, response.body
24 | @user.followers.each do |user|
25 | assert_select "a[href=?]", user_path(user)
26 | end
27 | end
28 |
29 | test "should follow a user the standard way" do
30 | assert_difference '@user.following.count', 1 do
31 | post relationships_path, params: { followed_id: @other.id }
32 | end
33 | end
34 |
35 | test "should follow a user with Ajax" do
36 | assert_difference '@user.following.count', 1 do
37 | post relationships_path, xhr: true, params: { followed_id: @other.id }
38 | end
39 | end
40 |
41 | test "should unfollow a user the standard way" do
42 | @user.follow(@other)
43 | relationship = @user.active_relationships.find_by(followed_id: @other.id)
44 | assert_difference '@user.following.count', -1 do
45 | delete relationship_path(relationship)
46 | end
47 | end
48 |
49 | test "should unfollow a user with Ajax" do
50 | @user.follow(@other)
51 | relationship = @user.active_relationships.find_by(followed_id: @other.id)
52 | assert_difference '@user.following.count', -1 do
53 | delete relationship_path(relationship), xhr: true
54 | end
55 | end
56 | end
--------------------------------------------------------------------------------
/test/integration/microposts_interface_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class MicropostsInterfaceTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | end
8 |
9 | test "micropost interface" do
10 | log_in_as(@user)
11 | get root_path
12 | assert_select 'div.pagination'
13 | # Invalid submission
14 | assert_no_difference 'Micropost.count' do
15 | post microposts_path, params: { micropost: { content: "" } }
16 | end
17 | assert_select 'div#error_explanation'
18 | # Valid submission
19 | content = "This micropost really ties the room together"
20 | assert_difference 'Micropost.count', 1 do
21 | post microposts_path, params: { micropost: { content: content } }
22 | end
23 | assert_redirected_to root_url
24 | follow_redirect!
25 | assert_match content, response.body
26 | # Delete a post.
27 | assert_select 'a', text: 'delete'
28 | first_micropost = @user.microposts.paginate(page: 1).first
29 | assert_difference 'Micropost.count', -1 do
30 | delete micropost_path(first_micropost)
31 | end
32 | # Visit a different user.
33 | get user_path(users(:archer))
34 | assert_select 'a', text: 'delete', count: 0
35 | end
36 | end
--------------------------------------------------------------------------------
/test/integration/password_resets_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PasswordResetsTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | ActionMailer::Base.deliveries.clear
7 | @user = users(:michael)
8 | end
9 |
10 | test "password resets" do
11 | get new_password_reset_path
12 | assert_template 'password_resets/new'
13 | # Invalid email
14 | post password_resets_path, params: { password_reset: { email: "" } }
15 | assert_not flash.empty?
16 | assert_template 'password_resets/new'
17 | # Valid email
18 | post password_resets_path,
19 | params: { password_reset: { email: @user.email } }
20 | assert_not_equal @user.reset_digest, @user.reload.reset_digest
21 | assert_equal 1, ActionMailer::Base.deliveries.size
22 | assert_not flash.empty?
23 | assert_redirected_to root_url
24 | # Password reset form
25 | user = assigns(:user)
26 | # Wrong email
27 | get edit_password_reset_path(user.reset_token, email: "")
28 | assert_redirected_to root_url
29 | # Inactive user
30 | user.toggle!(:activated)
31 | get edit_password_reset_path(user.reset_token, email: user.email)
32 | assert_redirected_to root_url
33 | user.toggle!(:activated)
34 | # Right email, wrong token
35 | get edit_password_reset_path('wrong token', email: user.email)
36 | assert_redirected_to root_url
37 | # Right email, right token
38 | get edit_password_reset_path(user.reset_token, email: user.email)
39 | assert_template 'password_resets/edit'
40 | assert_select "input[name=email][type=hidden][value=?]", user.email
41 | # Invalid password & confirmation
42 | patch password_reset_path(user.reset_token),
43 | params: { email: user.email,
44 | user: { password: "foobaz",
45 | password_confirmation: "barquux" } }
46 | assert_select 'div#error_explanation'
47 | # Empty password
48 | patch password_reset_path(user.reset_token),
49 | params: { email: user.email,
50 | user: { password: "",
51 | password_confirmation: "" } }
52 | assert_select 'div#error_explanation'
53 | # Valid password & confirmation
54 | patch password_reset_path(user.reset_token),
55 | params: { email: user.email,
56 | user: { password: "foobaz",
57 | password_confirmation: "foobaz" } }
58 | assert is_logged_in?
59 | assert_not flash.empty?
60 | assert_redirected_to user
61 | end
62 | end
--------------------------------------------------------------------------------
/test/integration/site_layout_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SiteLayoutTest < ActionDispatch::IntegrationTest
4 |
5 | test "layout links" do
6 | get root_path
7 | assert_template 'static_pages/home'
8 | assert_select "a[href=?]", root_path, count: 2
9 | assert_select "a[href=?]", help_path
10 | assert_select "a[href=?]", about_path
11 | assert_select "a[href=?]", contact_path
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/integration/users_edit_test.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'test_helper'
3 |
4 | class UsersEditTest < ActionDispatch::IntegrationTest
5 |
6 | def setup
7 | @user = users(:michael)
8 | end
9 |
10 | test "unsuccessful edit" do
11 | log_in_as(@user)
12 | get edit_user_path(@user)
13 | assert_template 'users/edit'
14 | patch user_path(@user), params: { user: { name: "",
15 | email: "foo@invalid",
16 | password: "foo",
17 | password_confirmation: "bar" } }
18 | assert_template 'users/edit'
19 | end
20 |
21 | test "successful edit with friendly forwarding" do
22 | get edit_user_path(@user)
23 | log_in_as(@user)
24 | assert_redirected_to edit_user_path(@user)
25 | name = "Foo Bar"
26 | email = "foo@bar.com"
27 | patch user_path(@user), params: { user: { name: name,
28 | email: email,
29 | password: "",
30 | password_confirmation: "" } }
31 | assert_not flash.empty?
32 | assert_redirected_to @user
33 | @user.reload
34 | assert_equal name, @user.name
35 | assert_equal email, @user.email
36 | end
37 | end
--------------------------------------------------------------------------------
/test/integration/users_index_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersIndexTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @admin = users(:michael)
7 | @non_admin = users(:archer)
8 | end
9 |
10 | test "index as admin including pagination and delete links" do
11 | log_in_as(@admin)
12 | get users_path
13 | assert_template 'users/index'
14 | assert_select 'div.pagination'
15 | first_page_of_users = User.paginate(page: 1)
16 | first_page_of_users.each do |user|
17 | assert_select 'a[href=?]', user_path(user), text: user.name
18 | unless user == @admin
19 | assert_select 'a[href=?]', user_path(user), text: 'delete'
20 | end
21 | end
22 | assert_difference 'User.count', -1 do
23 | delete user_path(@non_admin)
24 | end
25 | end
26 |
27 | test "index as non-admin" do
28 | log_in_as(@non_admin)
29 | get users_path
30 | assert_select 'a', text: 'delete', count: 0
31 | end
32 | end
--------------------------------------------------------------------------------
/test/integration/users_login_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersLoginTest < ActionDispatch::IntegrationTest
4 | def setup
5 | @user = users(:michael)
6 | end
7 |
8 | test "login with invalid information" do
9 | get login_path
10 | assert_template 'sessions/new'
11 | post login_path, params: { session: { email: "", password: "" } }
12 | assert_template 'sessions/new'
13 | assert_not flash.empty?
14 | get root_path
15 | assert flash.empty?
16 | end
17 |
18 | test "login with valid information followed by logout" do
19 | get login_path
20 | post login_path, params: { session: { email: @user.email,
21 | password: 'password' } }
22 | assert is_logged_in?
23 | assert_redirected_to @user
24 | follow_redirect!
25 | assert_template 'users/show'
26 | assert_select "a[href=?]", login_path, count: 0
27 | assert_select "a[href=?]", logout_path
28 | assert_select "a[href=?]", user_path(@user)
29 | delete logout_path
30 | assert_not is_logged_in?
31 | assert_redirected_to root_url
32 | # Simulate a user clicking logout in a second window.
33 | delete logout_path
34 | follow_redirect!
35 | assert_select "a[href=?]", login_path
36 | assert_select "a[href=?]", logout_path, count: 0
37 | assert_select "a[href=?]", user_path(@user), count: 0
38 | end
39 |
40 | test "login with remembering" do
41 | log_in_as(@user, remember_me: '1')
42 | assert_not_nil cookies['remember_token']
43 | end
44 |
45 | test "login without remembering" do
46 | log_in_as(@user, remember_me: '0')
47 | assert_nil cookies['remember_token']
48 | end
49 | end
--------------------------------------------------------------------------------
/test/integration/users_profile_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersProfileTest < ActionDispatch::IntegrationTest
4 | include ApplicationHelper
5 |
6 | def setup
7 | @user = users(:michael)
8 | end
9 |
10 | test "profile display" do
11 | get user_path(@user)
12 | assert_template 'users/show'
13 | assert_select 'title', full_title(@user.name)
14 | assert_select 'h1', text: @user.name
15 | assert_select 'h1>img.gravatar'
16 | assert_match @user.microposts.count.to_s, response.body
17 | assert_select 'div.pagination'
18 | @user.microposts.paginate(page: 1).each do |micropost|
19 | assert_match micropost.content, response.body
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/integration/users_signup_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersSignupTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | ActionMailer::Base.deliveries.clear
7 | end
8 |
9 | test "invalid signup information" do
10 | get signup_path
11 | assert_no_difference 'User.count' do
12 | post users_path, params: { user: { name: "",
13 | email: "user@invalid",
14 | password: "foo",
15 | password_confirmation: "bar" } }
16 | end
17 | assert_template 'users/new'
18 | assert_select 'div#error_explanation'
19 | assert_select 'div.field_with_errors'
20 | end
21 |
22 | test "valid signup information with account activation" do
23 | get signup_path
24 | assert_difference 'User.count', 1 do
25 | post users_path, params: { user: { name: "Example User",
26 | email: "user@example.com",
27 | password: "password",
28 | password_confirmation: "password" } }
29 | end
30 | assert_equal 1, ActionMailer::Base.deliveries.size
31 | user = assigns(:user)
32 | assert_not user.activated?
33 | # Try to log in before activation.
34 | log_in_as(user)
35 | assert_not is_logged_in?
36 | # Invalid activation token
37 | get edit_account_activation_path("invalid token", email: user.email)
38 | assert_not is_logged_in?
39 | # Valid token, wrong email
40 | get edit_account_activation_path(user.activation_token, email: 'wrong')
41 | assert_not is_logged_in?
42 | # Valid activation token
43 | get edit_account_activation_path(user.activation_token, email: user.email)
44 | assert user.reload.activated?
45 | follow_redirect!
46 | assert_template 'users/show'
47 | assert is_logged_in?
48 | end
49 | end
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/mailers/.keep
--------------------------------------------------------------------------------
/test/mailers/previews/user_mailer_preview.rb:
--------------------------------------------------------------------------------
1 | # Preview all emails at http://localhost:3000/rails/mailers/user_mailer
2 | class UserMailerPreview < ActionMailer::Preview
3 |
4 | # Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
5 | def account_activation
6 | user = User.first
7 | user.activation_token = User.new_token
8 | UserMailer.account_activation(user)
9 | end
10 |
11 | # Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
12 | def password_reset
13 | user = User.first
14 | user.reset_token = User.new_token
15 | UserMailer.password_reset(user)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/mailers/user_mailer_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserMailerTest < ActionMailer::TestCase
4 |
5 | test "account_activation" do
6 | user = users(:michael)
7 | user.activation_token = User.new_token
8 | mail = UserMailer.account_activation(user)
9 | assert_equal "Account activation", mail.subject
10 | assert_equal [user.email], mail.to
11 | assert_equal ["noreply@example.com"], mail.from
12 | assert_match user.name, mail.body.encoded
13 | assert_match user.activation_token, mail.body.encoded
14 | assert_match CGI.escape(user.email), mail.body.encoded
15 | end
16 |
17 | test "password_reset" do
18 | user = users(:michael)
19 | user.reset_token = User.new_token
20 | mail = UserMailer.password_reset(user)
21 | assert_equal "Password reset", mail.subject
22 | assert_equal [user.email], mail.to
23 | assert_equal ["noreply@example.com"], mail.from
24 | assert_match user.reset_token, mail.body.encoded
25 | assert_match CGI.escape(user.email), mail.body.encoded
26 | end
27 | end
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/test/models/.keep
--------------------------------------------------------------------------------
/test/models/micropost_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: microposts
4 | #
5 | # id :integer not null, primary key
6 | # content :text
7 | # picture :string
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | # user_id :integer
11 | #
12 | # Indexes
13 | #
14 | # index_microposts_on_user_id (user_id)
15 | #
16 |
17 | require 'test_helper'
18 |
19 | class MicropostTest < ActiveSupport::TestCase
20 |
21 | def setup
22 | @user = users(:michael)
23 | # This code is not idiomatically correct.
24 | @micropost = @user.microposts.build(content: "Lorem ipsum")
25 | end
26 |
27 | test "should be valid" do
28 | assert @micropost.valid?
29 | end
30 |
31 | test "user id should be present" do
32 | @micropost.user_id = nil
33 | assert_not @micropost.valid?
34 | end
35 |
36 | test "content should be present" do
37 | @micropost.content = " "
38 | assert_not @micropost.valid?
39 | end
40 |
41 | test "content should be at most 140 characters" do
42 | @micropost.content = "a" * 141
43 | assert_not @micropost.valid?
44 | end
45 |
46 | test "order should be most recent first" do
47 | assert_equal microposts(:most_recent), Micropost.first
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/test/models/relationship_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: relationships
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # followed_id :integer
9 | # follower_id :integer
10 | #
11 | # Indexes
12 | #
13 | # index_relationships_on_followed_id (followed_id)
14 | # index_relationships_on_follower_id (follower_id)
15 | # index_relationships_on_follower_id_and_followed_id (follower_id,followed_id) UNIQUE
16 | #
17 |
18 | require 'test_helper'
19 |
20 | class RelationshipTest < ActiveSupport::TestCase
21 |
22 | def setup
23 | @relationship = Relationship.new(follower_id: users(:michael).id,
24 | followed_id: users(:archer).id)
25 | end
26 |
27 | test "should be valid" do
28 | @relationship.valid?
29 | assert @relationship.valid?
30 | end
31 |
32 | test "should require a follower_id" do
33 | @relationship.follower_id = nil
34 | assert_not @relationship.valid?
35 | end
36 |
37 | test "should require a followed_id" do
38 | @relationship.followed_id = nil
39 | assert_not @relationship.valid?
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 | require "minitest/reporters"
5 | Minitest::Reporters.use!
6 |
7 | class ActiveSupport::TestCase
8 | fixtures :all
9 |
10 | # Returns true if a test user is logged in.
11 | def is_logged_in?
12 | !session[:user_id].nil?
13 | end
14 |
15 | # Log in as a particular user.
16 | def log_in_as(user)
17 | session[:user_id] = user.id
18 | end
19 | end
20 |
21 | class ActionDispatch::IntegrationTest
22 |
23 | # Log in as a particular user.
24 | def log_in_as(user, password: 'password', remember_me: '1')
25 | post login_path, params: { session: { email: user.email,
26 | password: password,
27 | remember_me: remember_me } }
28 | end
29 | end
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/tmp/.keep
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vasilakisfil/rails5_api_tutorial/e4e4ea7a847a1268d49168fdec68d47d3707ad43/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------