├── .all-contributorsrc ├── .dockerignore ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.md ├── README.md ├── docker-compose.yml ├── docs ├── devise │ ├── activejob-integration.md │ ├── additional_information.md │ ├── bug_reports.md │ ├── configuring-controllers.md │ ├── configuring-models.md │ ├── configuring-multiple-models.md │ ├── configuring-routes.md │ ├── configuring-views.md │ ├── contributing.md │ ├── controller_filters_and_helpers.md │ ├── example_applications.md │ ├── extensions.md │ ├── guides-list.md │ ├── i18n.md │ ├── installation.md │ ├── omniauth.md │ ├── other-orms.md │ ├── overview.md │ ├── password-reset-tokens-and-rails-logs.md │ ├── rails-api-mode.md │ ├── starting_with_rails.md │ ├── strong-parameters.md │ └── test-helpers.md └── rails │ ├── action_cable_overview.md │ ├── action_controller_overview.md │ ├── action_mailbox_basics.md │ ├── action_mailer_basics.md │ ├── action_text_overview.md │ ├── action_view_overview.md │ ├── active_job_basics.md │ ├── active_model_basics.md │ ├── active_record_basics.md │ ├── active_record_callbacks.md │ ├── active_record_migrations.md │ ├── active_record_multiple_databases.md │ ├── active_record_postgresql.md │ ├── active_record_querying.md │ ├── active_record_validations.md │ ├── active_storage_overview.md │ ├── active_support_core_extensions.md │ ├── active_support_instrumentation.md │ ├── api_app.md │ ├── api_documentation_guidelines.md │ ├── asset_pipeline.md │ ├── association_basics.md │ ├── autoloading_and_reloading_constants.md │ ├── caching_with_rails.md │ ├── command_line.md │ ├── configuring.md │ ├── contributing_to_ruby_on_rails.md │ ├── debugging_rails_applications.md │ ├── development_dependencies_install.md │ ├── engines.md │ ├── form_helpers.md │ ├── generators.md │ ├── getting_started.md │ ├── i18n.md │ ├── initialization.md │ ├── layouts_and_rendering.md │ ├── maintenance_policy.md │ ├── plugins.md │ ├── rails_application_templates.md │ ├── rails_on_rack.md │ ├── routing.md │ ├── ruby_on_rails_guides_guidelines.md │ ├── security.md │ ├── testing.md │ ├── threading_and_code_execution.md │ └── working_with_javascript_in_rails.md ├── package-lock.json ├── package.json └── website ├── README.md ├── blog ├── 2016-03-11-blog-post.md ├── 2017-04-10-blog-post-two.md ├── 2017-09-25-testing-rss.md ├── 2017-09-26-adding-rss.md └── 2017-10-24-new-version-1.0.0.md ├── core └── Footer.js ├── package-lock.json ├── package.json ├── pages └── en │ └── index.js ├── sidebars.json ├── siteConfig.js └── static ├── css └── custom.css └── img ├── favicon.ico ├── logo-rails-setup.png ├── oss_logo.png ├── rails-setup-logo-red.png ├── rails-setup-logo-white.png ├── undraw_books.svg ├── undraw_code_review.svg ├── undraw_monitor.svg ├── undraw_note_list.svg ├── undraw_online.svg ├── undraw_open_source.svg ├── undraw_operating_system.svg ├── undraw_react.svg ├── undraw_tweetstorm.svg └── undraw_youtube_tutorial.svg /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "rails-setup", 3 | "projectOwner": "HenryTabima", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "none", 12 | "contributors": [ 13 | { 14 | "login": "HenryTabima", 15 | "name": "Henry Tabima Giraldo", 16 | "avatar_url": "https://avatars0.githubusercontent.com/u/12721896?v=4", 17 | "profile": "http://henrytabima.com", 18 | "contributions": [ 19 | "doc" 20 | ] 21 | } 22 | ], 23 | "contributorsPerLine": 7 24 | } 25 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | */node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | 5 | lib/core/metadata.js 6 | lib/core/MetadataBlog.js 7 | 8 | website/translated_docs 9 | website/build/ 10 | website/yarn.lock 11 | website/node_modules 12 | website/i18n/* 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | First off, thank you for considering contributing to Rails-Setup. It’s people like you that make this project great. 4 | 5 | ## How to 6 | 7 | * Make sure that nobody else is already working on what you want to contribute (check Issues and PRs). 8 | * Raise an issue explaining what you want in the project and if you are going to take care of it. 9 | * fork the project and work on a different branch from master. 10 | * send a pull request 11 | 12 | ## Type of contributions 13 | 14 | * [Misspelling fixes](#misspelling-fixes) 15 | * [Fix documentation issues](#fix-documentation-issues) 16 | * [Add documentation for common Rails related libraries](#add-documentation-for-common-rails-related-libraries) 17 | * [Enhancing the website](#enhancing-the-website) 18 | 19 | ### Misspelling fixes 20 | 21 | As humans we are prone to erros, including misspelling. if you see any please rise an issue. 22 | 23 | ### Fix documentation issues 24 | 25 | Most of the documentation added is just copied from the original projects, sometimes it comes with links to images and another pages that get broke once you put in here. you can help fixing that kind of things. 26 | 27 | ### Add documentation for common Rails related libraries 28 | 29 | You could bring here documentation from another project that usually dont have their own documentation website or maybe their website is not friendly enough. 30 | 31 | ### Enhancing the website 32 | 33 | If you have cool ideas to imporve the look and feel of the index or any other page, please raise an issue explaining what do you have in mind. 34 | 35 | ## Roadmap 36 | 37 | the idea is to have documentatios by topic and library. like: 38 | 39 | * Rails 40 | * Authentication 41 | * devise 42 | * jwt 43 | * others libraries... 44 | * Testing 45 | * minitest 46 | * rspec 47 | * others... 48 | * Commonly used 49 | * Faker 50 | * Factory bot 51 | 52 | The ultimate goal is to have all what you need to achieve whatever you want in your rails project. All in one place. all easy to navigate. 53 | 54 | ## Getting in touch 55 | 56 | Feel free to get in touch. send me an email, or even better, tweet me [@HenryTabimaG](https://twitter.com/HenryTabimaG) -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.11.4 2 | 3 | WORKDIR /app/website 4 | 5 | EXPOSE 3000 35729 6 | COPY ./docs /app/docs 7 | COPY ./website /app/website 8 | RUN yarn install 9 | 10 | CMD ["yarn", "start"] 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-present, Henry Tabima Giraldo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rails Setup 2 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors) 3 | 4 | [Visit Rails-Setup website](https://HenryTabima.github.io/rails-setup) 5 | 6 | this is a Project to collect in one place and in a friendly way the documentation for rails and commonly used related libraries 7 | 8 | ## Getting started 9 | 10 | this site is built on top of docusaurus, [see respective documentation](https://docusaurus.io/docs/en/next/installation) to getting started with this project. 11 | 12 | ## Contributing 13 | 14 | We appreciate any contribution you would like to do. To know what you can do the steps to do it, please follow the [contribution guidelines](CONTRIBUTING.md). 15 | 16 | Summary: 17 | * Make sure that nobody else is already working on what you want to contribute (check Issues and PRs). 18 | * Raise an issue explaining what you want in the project and if you are going to take care of it. 19 | * fork the project and work on a different branch from master. 20 | * send a pull request 21 | 22 | ## Todos 23 | 24 | List of possible contributions that you can do to this project 25 | 26 | * add a list of the projects added to the rails-setup website and their last update date 27 | * fix the broken URLs in the links of the rails documentation files (they are just as I copied from the source documentation site) 28 | * add documentation for other common project used with rails (like devise, factory bot and others) 29 | 30 | ## Code of conduct 31 | 32 | Read it in detail [here](CODE_OF_CONDUCT.md). 33 | 34 | ## License 35 | 36 | This project is under [MIT license](LICENSE.md) 37 | 38 | ## Contributors 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Henry Tabima Giraldo
Henry Tabima Giraldo

📖
47 | 48 | 49 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | docusaurus: 5 | build: . 6 | ports: 7 | - 3000:3000 8 | - 35729:35729 9 | volumes: 10 | - ./docs:/app/docs 11 | - ./website/blog:/app/website/blog 12 | - ./website/core:/app/website/core 13 | - ./website/i18n:/app/website/i18n 14 | - ./website/pages:/app/website/pages 15 | - ./website/static:/app/website/static 16 | - ./website/sidebars.json:/app/website/sidebars.json 17 | - ./website/siteConfig.js:/app/website/siteConfig.js 18 | working_dir: /app/website 19 | -------------------------------------------------------------------------------- /docs/devise/activejob-integration.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: activejob-integration 3 | title: ActiveJob integration 4 | --- 5 | 6 | If you are using Rails 4.2 and ActiveJob to deliver ActionMailer messages in the 7 | background through a queuing back-end, you can send Devise emails through your 8 | existing queue by overriding the `send_devise_notification` method in your model. 9 | 10 | ```ruby 11 | def send_devise_notification(notification, *args) 12 | devise_mailer.send(notification, self, *args).deliver_later 13 | end 14 | ``` -------------------------------------------------------------------------------- /docs/devise/additional_information.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: additional-information 3 | title: Additional information 4 | --- 5 | 6 | ## Heroku 7 | 8 | Using Devise on Heroku with Ruby on Rails 3.2 requires setting: 9 | 10 | ```ruby 11 | config.assets.initialize_on_precompile = false 12 | ``` 13 | 14 | Read more about the potential issues at http://guides.rubyonrails.org/asset_pipeline.html 15 | 16 | ## Warden 17 | 18 | Devise is based on Warden, which is a general Rack authentication framework created by Daniel Neighman. We encourage you to read more about Warden here: 19 | 20 | https://github.com/hassox/warden 21 | 22 | ## DEVISE_ORM 23 | 24 | 25 | ## BUNDLE_GEMFILE 26 | We can use this variable to tell bundler what Gemfile it should use (instead of the one in the current directory). 27 | Inside the [gemfiles](https://github.com/plataformatec/devise/tree/master/gemfiles) directory, we have one for each version of Rails we support. When you send us a pull request, it may happen that the test suite breaks on Travis using some of them. If that's the case, you can simulate the same environment using the `BUNDLE_GEMFILE` variable. 28 | For example, if the tests broke using Ruby 2.4.2 and Rails 4.1, you can do the following: 29 | ```bash 30 | rbenv shell 2.4.2 # or rvm use 2.4.2 31 | BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install 32 | BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bin/test 33 | ``` 34 | 35 | You can also combine both of them if the tests broke for Mongoid: 36 | ```bash 37 | BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install 38 | BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable DEVISE_ORM=mongoid bin/test 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/devise/bug_reports.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: bug-reports 3 | title: Bug reports 4 | --- 5 | If you were linked to this page from Github Issues Tracker or Mailing List, don't worry! We still love you and want your feedback, but you may have left some important information out of your report. Please read below. 6 | 7 | First off: if you have questions about Devise, please search the Wiki and Google Group to see if your questions have already been answered. If not, please post your questions to the Google Group. *Do not use the GitHub Issues tracker for questions* 8 | 9 | 1) Before submitting a bug report: 10 | 11 | * Ensure you are using latest devise version. If you are using Devise from git repository with bundler, be sure to run `bundle update`. Maybe your error was already fixed. 12 | * Search the existing GitHub Issues to make sure your issue hasn't already been reported. If not, proceed. 13 | * If you found a security bug, do *NOT* use the GitHub Issue tracker. Please send an email to opensource@plataformatec.com.br. 14 | 15 | 2) When submitting a bug report: 16 | 17 | * Include Ruby, Warden, Devise, OrmAdapter (if using Devise 1.2 forward) and Rails versions in the report; 18 | * Include oauth2 and faraday gem versions if using OAuth; 19 | * Include error class, message and backtrace if you are getting an error; 20 | 21 | 3) The information above can help us spot an obvious bug, however most bugs may require you to investigate deeper. In such cases: 22 | 23 | * Please try to reproduce the bug in devise test suite. Devise test suite is a Rails application as any other (check test/rails_app in the repository) making it easy to reproduce bugs; 24 | * Or try to isolate the bug in a smaller application and push it to github; 25 | 26 | Remember that this is an open-source project, and the contributions of volunteers have made it possible. Please be polite and provide as much information as possible so that we can help you! 27 | 28 | 4) Our Issues Tracker is available here: 29 | 30 | http://github.com/plataformatec/devise/issues 31 | -------------------------------------------------------------------------------- /docs/devise/configuring-controllers.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring-controllers 3 | title: Configuring controllers 4 | --- 5 | 6 | If the customization at the views level is not enough, you can customize each controller by following these steps: 7 | 8 | 1. Create your custom controllers using the generator which requires a scope: 9 | 10 | ```console 11 | $ rails generate devise:controllers [scope] 12 | ``` 13 | 14 | If you specify `users` as the scope, controllers will be created in `app/controllers/users/`. 15 | And the sessions controller will look like this: 16 | 17 | ```ruby 18 | class Users::SessionsController < Devise::SessionsController 19 | # GET /resource/sign_in 20 | # def new 21 | # super 22 | # end 23 | ... 24 | end 25 | ``` 26 | (Use the -c flag to specify a controller, for example: `rails generate devise:controllers users -c=sessions`) 27 | 28 | 2. Tell the router to use this controller: 29 | 30 | ```ruby 31 | devise_for :users, controllers: { sessions: 'users/sessions' } 32 | ``` 33 | 34 | 3. Copy the views from `devise/sessions` to `users/sessions`. Since the controller was changed, it won't use the default views located in `devise/sessions`. 35 | 36 | 4. Finally, change or extend the desired controller actions. 37 | 38 | You can completely override a controller action: 39 | 40 | ```ruby 41 | class Users::SessionsController < Devise::SessionsController 42 | def create 43 | # custom sign-in code 44 | end 45 | end 46 | ``` 47 | 48 | Or you can simply add new behaviour to it: 49 | 50 | ```ruby 51 | class Users::SessionsController < Devise::SessionsController 52 | def create 53 | super do |resource| 54 | BackgroundWorker.trigger(resource) 55 | end 56 | end 57 | end 58 | ``` 59 | 60 | This is useful for triggering background jobs or logging events during certain actions. 61 | 62 | Remember that Devise uses flash messages to let users know if sign in was successful or unsuccessful. Devise expects your application to call `flash[:notice]` and `flash[:alert]` as appropriate. Do not print the entire flash hash, print only specific keys. In some circumstances, Devise adds a `:timedout` key to the flash hash, which is not meant for display. Remove this key from the hash if you intend to print the entire hash. 63 | -------------------------------------------------------------------------------- /docs/devise/configuring-models.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring-models 3 | title: Configuring Models 4 | --- 5 | 6 | The Devise method in your models also accepts some options to configure its modules. For example, you can choose the cost of the hashing algorithm with: 7 | 8 | ```ruby 9 | devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 12 10 | ``` 11 | 12 | Besides `:stretches`, you can define `:pepper`, `:encryptor`, `:confirm_within`, `:remember_for`, `:timeout_in`, `:unlock_in` among other options. For more details, see the initializer file that was created when you invoked the "devise:install" generator described above. This file is usually located at `/config/initializers/devise.rb`. 13 | -------------------------------------------------------------------------------- /docs/devise/configuring-multiple-models.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring-multiple-models 3 | title: Configuring multiple models 4 | --- 5 | 6 | Devise allows you to set up as many Devise models as you want. If you want to have an Admin model with just authentication and timeout features, in addition to the User model above, just run: 7 | 8 | ```ruby 9 | # Create a migration with the required fields 10 | create_table :admins do |t| 11 | t.string :email 12 | t.string :encrypted_password 13 | t.timestamps null: false 14 | end 15 | 16 | # Inside your Admin model 17 | devise :database_authenticatable, :timeoutable 18 | 19 | # Inside your routes 20 | devise_for :admins 21 | 22 | # Inside your protected controller 23 | before_action :authenticate_admin! 24 | 25 | # Inside your controllers and views 26 | admin_signed_in? 27 | current_admin 28 | admin_session 29 | ``` 30 | 31 | Alternatively, you can simply run the Devise generator. 32 | 33 | Keep in mind that those models will have completely different routes. They **do not** and **cannot** share the same controller for sign in, sign out and so on. In case you want to have different roles sharing the same actions, we recommend that you use a role-based approach, by either providing a role column or using a dedicated gem for authorization. -------------------------------------------------------------------------------- /docs/devise/configuring-routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring-routes 3 | title: Configuring routes 4 | --- 5 | 6 | 7 | Devise also ships with default routes. If you need to customize them, you should probably be able to do it through the devise_for method. It accepts several options like :class_name, :path_prefix and so on, including the possibility to change path names for I18n: 8 | 9 | ```ruby 10 | devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' } 11 | ``` 12 | 13 | Be sure to check `devise_for` [documentation](http://www.rubydoc.info/github/plataformatec/devise/master/ActionDispatch/Routing/Mapper%3Adevise_for) for details. 14 | 15 | If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is create your routes normally and wrap them in a `devise_scope` block in the router: 16 | 17 | ```ruby 18 | devise_scope :user do 19 | get 'sign_in', to: 'devise/sessions#new' 20 | end 21 | ``` 22 | 23 | This way, you tell Devise to use the scope `:user` when "/sign_in" is accessed. Notice `devise_scope` is also aliased as `as` in your router. 24 | 25 | Please note: You will still need to add `devise_for` in your routes in order to use helper methods such as `current_user`. 26 | 27 | ```ruby 28 | devise_for :users, skip: :all 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/devise/configuring-views.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring-views 3 | title: Configuring views 4 | --- 5 | We built Devise to help you quickly develop an application that uses authentication. However, we don't want to be in your way when you need to customize it. 6 | 7 | Since Devise is an engine, all its views are packaged inside the gem. These views will help you get started, but after some time you may want to change them. If this is the case, you just need to invoke the following generator, and it will copy all views to your application: 8 | 9 | ```console 10 | $ rails generate devise:views 11 | ``` 12 | 13 | If you have more than one Devise model in your application (such as `User` and `Admin`), you will notice that Devise uses the same views for all models. Fortunately, Devise offers an easy way to customize views. All you need to do is set `config.scoped_views = true` inside the `config/initializers/devise.rb` file. 14 | 15 | After doing so, you will be able to have views based on the role like `users/sessions/new` and `admins/sessions/new`. If no view is found within the scope, Devise will use the default view at `devise/sessions/new`. You can also use the generator to generate scoped views: 16 | 17 | ```console 18 | $ rails generate devise:views users 19 | ``` 20 | 21 | If you would like to generate only a few sets of views, like the ones for the `registerable` and `confirmable` module, 22 | you can pass a list of modules to the generator with the `-v` flag. 23 | 24 | ```console 25 | $ rails generate devise:views -v registrations confirmations 26 | ``` -------------------------------------------------------------------------------- /docs/devise/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: contributing 3 | title: Contributing 4 | --- 5 | We hope that you will consider contributing to Devise. You can contribute in many ways. For example, you might: 6 | 7 | * add documentation and "how-to" articles to the README or Wiki. 8 | * help people with the questions they ask on the Google Group. 9 | * create an extension that provides additional functionality above and beyond Devise itself. 10 | * improve the existing example applications to demonstrate features in Devise. 11 | * improve and/or add new I18n translations 12 | * hack on Devise itself by fixing bugs you've found in the GitHub Issue tracker or adding new features to Devise. 13 | 14 | When contributing to Devise, we ask that you: 15 | 16 | * let us know what you plan in the GitHub Issue tracker so we can provide feedback. 17 | * provide tests and documentation whenever possible. It is very unlikely that we will accept new features or functionality into Devise without the proper testing and documentation. When fixing a bug, provide a failing test case that your patch solves. 18 | * open a GitHub Pull Request with your patches and we will review your contribution and respond as quickly as possible. Keep in mind that this is an open source project, and it may take us some time to get back to you. Your patience is very much appreciated. 19 | 20 | We have a long list of valued contributors. Check them all at: 21 | 22 | http://github.com/plataformatec/devise/contributors 23 | 24 | = Testing 25 | 26 | You can run the entire test suite with the default rake task: 27 | 28 | ``` 29 | rake 30 | ``` 31 | 32 | To run a single test, specify the file in the `TEST` environment variable: 33 | 34 | ``` 35 | rake test TEST=test/controllers/passwords_controller_test.rb 36 | ``` -------------------------------------------------------------------------------- /docs/devise/controller_filters_and_helpers.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: controller-filters-and-helpers 3 | title: Controller filters and helpers 4 | --- 5 | 6 | Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_action (assuming your devise model is 'User'): 7 | 8 | ```ruby 9 | before_action :authenticate_user! 10 | ``` 11 | 12 | For Rails 5, note that `protect_from_forgery` is no longer prepended to the `before_action` chain, so if you have set `authenticate_user` before `protect_from_forgery`, your request will result in "Can't verify CSRF token authenticity." To resolve this, either change the order in which you call them, or use `protect_from_forgery prepend: true`. 13 | 14 | If your devise model is something other than User, replace "_user" with "_yourmodel". The same logic applies to the instructions below. 15 | 16 | To verify if a user is signed in, use the following helper: 17 | 18 | ```ruby 19 | user_signed_in? 20 | ``` 21 | 22 | For the current signed-in user, this helper is available: 23 | 24 | ```ruby 25 | current_user 26 | ``` 27 | 28 | You can access the session for this scope: 29 | 30 | ```ruby 31 | user_session 32 | ``` 33 | 34 | After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect to. For instance, when using a `:user` resource, the `user_root_path` will be used if it exists; otherwise, the default `root_path` will be used. This means that you need to set the root inside your routes: 35 | 36 | ```ruby 37 | root to: 'home#index' 38 | ``` 39 | 40 | You can also override `after_sign_in_path_for` and `after_sign_out_path_for` to customize your redirect hooks. 41 | 42 | Notice that if your Devise model is called `Member` instead of `User`, for example, then the helpers available are: 43 | 44 | ```ruby 45 | before_action :authenticate_member! 46 | 47 | member_signed_in? 48 | 49 | current_member 50 | 51 | member_session 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/devise/example_applications.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: example-applications 3 | title: Example Applications 4 | --- 5 | 6 | A list of example Rails applications that demonstrate how to use Devise. When adding your own examples, please add both Rails and Devise versions to your descriptions. 7 | 8 | ## Rails 5.0.0 Example 9 | 10 | | Author | Project | Comments | 11 | |--------|---------|----------| 12 | | bilal basharat | "Devise with Rails":https://github.com/bilalbash/rails_5_devise_app | Rails 5.0.0, Devise 4.2.0, plus Bootstrap | 13 | | sachin | "Rails5 skeleton":https://github.com/sachin/rails5-skeleton | Rails 5.0.0.1, Devise 4.2.0, plus Bootstrap4, Active Admin, STI for App patrons| 14 | | RailsApps | "Devise and Rails":https://github.com/RailsApps/rails-devise | Rails 5.0, Devise 4.2, plus Bootstrap or Foundation | 15 | | RailsApps | "Devise and Pundit and Rails":https://github.com/RailsApps/rails-devise-pundit | Rails 5.0, Devise 4.2, showing how to use Pundit for authorization | 16 | | Mohit Jain | "Devise, Facebook, Twitter, Google, Github, Linkedin":https://github.com/mohitjain/social-login-in-rails | Rails 5.1.5, Devise 4.4.1, Bootstrap, TurboLinks, carrierwave, MySql, Active Record. with "Demo":http://social-login-in-rails.herokuapp.com/ | 17 | | Joshua Needham | "Rails 5 Devise Omniauth Omniauth-Facebook Bootstrap":https://github.com/joshuaneedham/rails-5-devise-omniauth-facebook-bootstrap | Rails 5.2.2.1, Devise 4.6.1, OmniAuth 1.9.0, sassc 2.0.1, Bootstrap 4.3.1, TurboLinks, Active Record.| 18 | 19 | 20 | ## Rails 4.0 Examples 21 | 22 | | Author | Project | Comments | 23 | |--------|---------|----------| 24 | | Jay Shepherd | "Devise 3 example for Rails 4":https://github.com/jayshepherd/devise_example | Rails 4, Devise 3.0.0rc | 25 | | Michael Lang | "Lazy Registration":https://github.com/mwlang/lazy_registration_demos | Rails 4, Ruby 2, Devise 3.0 | 26 | | Abhilash M A | "Token based authentication for API":https://github.com/abhidsm/devise-token-api | Rails 4, Ruby 2, Devise 3.0 | 27 | | Ritesh Kumar | "Devise, Mongoid, MySQL":https://github.com/Ritesh-Kumar/rails4_mysql_mongo | Base Application of Rails 4.0 using both MySQL and Mongo, Devise 3, CanCan, OmniAuth and Twitter Bootstrap | 28 | | Rendered Text | "BaseApp":https://github.com/renderedtext/base-app | Rails 4, PostgreSQL, jQuery, RSpec, Cucumber, Devise 3.2, FB login (OmniAuth), admin system | 29 | 30 | 31 | ## Older Examples 32 | 33 | | Author | Project | Comments | 34 | |--------|---------|----------| 35 | | Andi Altendorfer | "Community Base Application (CBA)":http://github.com/iboard/CBA | Rails 3.2, Devise 1.4.2, OmniAuth 1.0.2, Mongoid, CanCan, Paperclip, etc. | 36 | | W.R. de Vos | "rails_template":https://github.com/foxycoder/rails_template | Rails 3.2, Devise 2.1.2, Oauth with Facebook and Google login (OmniAuth 1.1.1), Mongoid, Cancan, Carrierwave, Rspec, Cucumber | 37 | -------------------------------------------------------------------------------- /docs/devise/extensions.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: extensions 3 | title: List of 3rd party Devise extensions. 4 | sidebar_label: Extensions 5 | --- 6 | 7 | ## ORM Support 8 | 9 | *mm-devise* - "Devise - MongoMapper":http://github.com/kristianmandrup/mm-devise 10 | 11 | *dm-devise* - "Devise - DataMapper":http://github.com/jm81/dm-devise 12 | 13 | *devise-couch* - "Devise - Couch DB":http://github.com/shenoudab/devise_couch 14 | 15 | *devise-ripple* - "Devise - Riak":http://github.com/frank06/devise-ripple 16 | 17 | *cequel-devise* - "Devise - Cassandra":https://github.com/cequel/cequel-devise 18 | 19 | ## Encryption Support 20 | 21 | *devise-encryptable* - adds support of other authentication mechanisms besides the built-in Bcrypt (the default). 22 | "https://github.com/plataformatec/devise-encryptable":https://github.com/plataformatec/devise-encryptable 23 | 24 | *devise_aes_encryptable* - AES-256 Reversible Encryption 25 | "http://github.com/chicks/devise_aes_encryptable":http://github.com/chicks/devise_aes_encryptable 26 | 27 | *devise-argon2* - Support for Argon2i 28 | "https://github.com/erdostom/devise-argon2":https://github.com/erdostom/devise-argon2 29 | 30 | ## Mailing List Support 31 | 32 | *devise_campaignable* - Have your users automatically added to a mail campaign tool of your choice. Currently supports MailChimp but easy adaptation for CampaignMonitor. "https://github.com/SirRawlins/devise_campaignable":https://github.com/SirRawlins/devise_campaignable 33 | 34 | *devise_mailchimp* - MailChimp integration for Devise making it effortless for users to join mailing lists when they register their account. 35 | "http://jcnnghm.github.com/devise_mailchimp/":http://jcnnghm.github.com/devise_mailchimp/ 36 | 37 | h3. Miscellaneous 38 | 39 | *cantango* - Integrates Devise, Roles and CanCan with Permits for a Rails 3 app 40 | "http://github.com/kristianmandrup/cantango":http://github.com/kristianmandrup/cantango 41 | (Replaces *cream*, "http://github.com/kristianmandrup/cream":http://github.com/kristianmandrup/cream) 42 | 43 | *invitable* - Adds support for send account invitations by email. 44 | "http://github.com/scambra/devise_invitable":http://github.com/scambra/devise_invitable 45 | 46 | *devise_traceable* - Tracing Devise Model (Model Stamp login and logout) 47 | "http://github.com/shenoudab/devise_traceable":http://github.com/shenoudab/devise_traceable 48 | 49 | *devise_lastseenable* - Just adds a last_seen datetime that's updated whenever authenticate! is called. 50 | "https://github.com/ctide/devise_lastseenable":https://github.com/ctide/devise_lastseenable 51 | 52 | *devise_security* - Add "enterprise" functionality (strong passwords, password expire..., new: captcha support) 53 | "https://github.com/devise-security/devise-security":https://github.com/devise-security/devise-security 54 | 55 | *devise-basecamper* - Add basecamp-style subdomain scoped authentication 56 | "https://github.com/digitalopera/devise-basecamper":https://github.com/digitalopera/devise-basecamper 57 | 58 | *devise-two-factor* - Barebones two-factor authentication support 59 | "https://github.com/tinfoil/devise-two-factor":https://github.com/tinfoil/devise-two-factor 60 | 61 | *two_factor_authentication* - Add two factor authentication, like Gmail 62 | "https://github.com/Houdini/two_factor_authentication":https://github.com/Houdini/two_factor_authentication 63 | 64 | *devise_account_expireable* - Expire a user account at a specific date / time. 65 | "https://github.com/j-mcnally/devise_account_expireable":https://github.com/j-mcnally/devise_account_expireable 66 | 67 | *devise_uid* - Add UID support to Devise. A lot of times, we want a unique ID representing the user model instead of its incremental ID in the database, for example, in API instead of exposing the primary key, we use a random generated unique string to indentify this user. 68 | "https://github.com/jingweno/devise_uid":https://github.com/jingweno/devise_uid 69 | 70 | *devise_session_expirable* - Devise timeoutable's paranoid cousin. Enforces time-limited sessions by rejecting sessions which are not timestamped. 71 | "https://github.com/teleological/devise_session_expirable":https://github.com/teleological/devise_session_expirable 72 | 73 | *devise_zxcvbn* - Reject weak passwords using zxcvbn. 74 | "https://github.com/bitzesty/devise_zxcvbn":https://github.com/bitzesty/devise_zxcvbn 75 | 76 | *devise_invalidatable* - Invalidate sessions from the server-side. 77 | "https://github.com/madkins/devise_invalidatable":https://github.com/madkins/devise_invalidatable 78 | 79 | *any_login* - easy login with any user to make your development life easier. 80 | "https://github.com/igorkasyanchuk/any_login":https://github.com/igorkasyanchuk/any_login 81 | 82 | *devise-verifiable* - Adds a second step to Devise's signup process. Useful if you want to collect extra information or verify user's identity through a 3rd-party service. "github.com/Rodrigora/devise-verifiable":https://github.com/Rodrigora/devise-verifiable 83 | 84 | *honeybadger* - When used together, exceptions reported to honeybadger will automatically be associated with the current Devise user. 85 | "https://github.com/honeybadger-io/honeybadger-ruby":https://github.com/honeybadger-io/honeybadger-ruby 86 | 87 | *devise-uncommon_password* - Prevents a user from using a password in the list of the 100 most common passwords. 88 | "https://github.com/HCLarsen/devise-uncommon_password":https://github.com/HCLarsen/devise-uncommon_password 89 | 90 | *devise-pwned_password* - checks user passwords against the "PwnedPasswords":https://haveibeenpwned.com/Passwords dataset. 91 | "https://github.com/michaelbanfield/devise-pwned_password":https://github.com/michaelbanfield/devise-pwned_password 92 | 93 | *devise_date_restrictable* - restrict a user’s account by date range (valid from/until/between). 94 | "https://github.com/jonpearse/devise_date_restrictable":https://github.com/jonpearse/devise_date_restrictable 95 | 96 | h3. External authentication integration 97 | 98 | *devise-browserid* - Adds support for Mozilla Persona / BrowserID authentication. 99 | "https://github.com/ringe/devise-browserid/":https://github.com/ringe/devise-browserid/ 100 | 101 | *facebook_connectable* - Adds support for Facebook Connect authentication, and optionally fetching user info from Facebook in the same step. 102 | "http://github.com/grimen/devise_facebook_connectable":http://github.com/grimen/devise_facebook_connectable 103 | 104 | *oauth2_authenticatable* - Adds support for OAuth2 (Facebook Graph) authentication. 105 | "http://github.com/bhbryant/devise_oauth2_authenticatable":http://github.com/bhbryant/devise_oauth2_authenticatable 106 | 107 | *oauth2_providable* - Adds an OAuth2 authentication layer to protect API resources. 108 | "https://github.com/socialcast/devise_oauth2_providable":https://github.com/socialcast/devise_oauth2_providable 109 | 110 | *devise-twitter* - Adds Sign in via Twitter and Connect your account to Twitter functionality 111 | "http://github.com/MSch/devise-twitter":http://github.com/MSch/devise-twitter 112 | 113 | *imapable* - Adds support for authentication via IMAP, a great solution for internal application where no LDAP server exists. 114 | "http://github.com/joshk/devise_imapable":http://github.com/joshk/devise_imapable 115 | 116 | *ldap_authenticatable* - Adds support for LDAP authentication via simple bind. 117 | "http://github.com/cschiewek/devise_ldap_authenticatable":http://github.com/cschiewek/devise_ldap_authenticatable 118 | 119 | *rpx_connectable* - Adds support for "RPX":http://www.rpxnow.com authentication. "RPX":http://www.rpxnow.com provides free and paid services to handle many authentication providers (facebook, twitter, OpenID...) using a single API. 120 | "http://github.com/slainer68/devise_rpx_connectable":http://github.com/slainer68/devise_rpx_connectable 121 | 122 | *cas_authenticatable* - Adds support for single sign-on via "CAS":http://www.jasig.org/cas and CAS-implementing servers. 123 | "http://github.com/nbudin/devise_cas_authenticatable":http://github.com/nbudin/devise_cas_authenticatable 124 | 125 | *openid_authenticatable* - Adds support for "OpenID":http://openid.net authentication. 126 | "http://github.com/nbudin/devise_openid_authenticatable":http://github.com/nbudin/devise_openid_authenticatable 127 | 128 | *devise_paypal* - Adds support for "Paypal":http://www.paypal.com authentication 129 | "http://github.com/dwilkie/devise_paypal":http://github.com/dwilkie/devise_paypal 130 | 131 | *devise_google_authenticator* - Adds support for "Google's Authenticator":http://code.google.com/p/google-authenticator/ 132 | "http://github.com/AsteriskLabs/devise_google_authenticator":http://github.com/AsteriskLabs/devise_google_authenticator 133 | 134 | *devise_shibboleth_authenticatable* - Adds support for "Shibboleth":http://shibboleth.net 135 | "https://github.com/jgeorge300/devise_shibboleth_authenticatable":https://github.com/jgeorge300/devise_shibboleth_authenticatable 136 | 137 | *devise-radius-authenticatable* - Adds support for authenticating against radius servers 138 | "https://github.com/cbascom/devise-radius-authenticatable":https://github.com/cbascom/devise-radius-authenticatable 139 | 140 | *devise-jwt* - JWT token authentication with devise 141 | "https://github.com/waiting-for-dev/devise-jwt":https://github.com/waiting-for-dev/devise-jwt -------------------------------------------------------------------------------- /docs/devise/guides-list.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: guides-list 3 | title: Guides list 4 | --- 5 | 6 | > Todo: move the guides to this site 7 | 8 | Feel free to add your own how-to and categorize it in this list. 9 | 10 | ## Upgrading 11 | 12 | * [Upgrade: General Instructions](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade:-General-Instructions) 13 | * [Upgrade to Devise 3.1](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-3.1) 14 | * [Upgrade to Devise 2.2](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.2) 15 | * [Upgrade to Devise 2.1](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.1) 16 | * [Upgrade to Devise 2.0](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0) 17 | * [Upgrade to Devise 2.0 migration schema style](https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0-migration-schema-style) 18 | * [Migration legacy database](https://github.com/plataformatec/devise/wiki/How-To:-Migration-legacy-database) 19 | 20 | ## Workflow Customization 21 | 22 | * [Automatically generate password for users (simpler registration)](https://github.com/plataformatec/devise/wiki/How-To:-Automatically-generate-password-for-users-%28simpler-registration%29) 23 | * [Change the default sign_in and sign_out routes](https://github.com/plataformatec/devise/wiki/How-To:-Change-the-default-sign_in-and-sign_out-routes) 24 | * [Change Default Sign_up Registration Path with Custom Path](https://github.com/plataformatec/devise/wiki/How-To:-Change-Default-Sign_up---Registration-Path-with-Custom-Path) 25 | * [Customize routes to user registration pages](https://github.com/plataformatec/devise/wiki/How-To:-Customize-routes-to-user-registration-pages) 26 | * [Redirect to a specific page on successful sign in out](https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in-out) 27 | * [Customize the redirect after a user edits their profile](https://github.com/plataformatec/devise/wiki/How-To:-Customize-the-redirect-after-a-user-edits-their-profile) 28 | * [Customize the redirect path after destroying a session (signing out)](https://github.com/plataformatec/devise/wiki/How-To:-Change-the-redirect-path-after-destroying-a-session-i.e.-signing-out) 29 | * [Override confirmations so users can pick their own passwords as part of confirmation activation](https://github.com/plataformatec/devise/wiki/How-To:-Override-confirmations-so-users-can-pick-their-own-passwords-as-part-of-confirmation-activation) 30 | * [Retain User Data after account Delete (soft delete)](https://github.com/plataformatec/devise/wiki/How-to:-Soft-delete-a-user-when-user-deletes-account) 31 | * [Use Omniauth in a localized scope](https://github.com/plataformatec/devise/wiki/How-To:-OmniAuth-inside-localized-scope) 32 | * [Redirect with locale after authentication failure](https://github.com/plataformatec/devise/wiki/How-To:--Redirect-with-locale-after-authentication-failure) 33 | * [Require admin to activate account before sign_in](https://github.com/plataformatec/devise/wiki/How-To:-Require-admin-to-activate-account-before-sign_in) 34 | * [Set up devise as a single user system](https://github.com/plataformatec/devise/wiki/How-To:-Set-up-devise-as-a-single-user-system) 35 | * [Two step confirmation](https://github.com/plataformatec/devise/wiki/How-To:-Two-step-confirmation) 36 | * [Redirect back to current page after sign in, sign out, sign up, update](https://github.com/plataformatec/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update) 37 | * [Redirect from HTTPS to HTTP on successful sign out](https://github.com/plataformatec/devise/wiki/How-To:-redirect-from-HTTPS-to-HTTP-on-successful-sign-out) 38 | * [Redirect to a specific page on successful sign in, sign up, or sign out](https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in,-sign-up,-or-sign-out) 39 | * [Redirect to a specific page when the user can not be authenticated](https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-when-the-user-can-not-be-authenticated) 40 | * [Do not redirect to login page after session timeout](https://github.com/plataformatec/devise/wiki/How-To:-Do-not-redirect-to-login-page-after-session-timeout) 41 | * [Create a guest user](https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user) 42 | * [Allow users to edit their password](https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password) 43 | * [Require authentication for all pages and avoid "You need to sign in..." message when hitting the application root](https://github.com/plataformatec/devise/wiki/How-To:-Require-authentication-for-all-pages) 44 | * [Use a custom email validator with Devise](https://github.com/plataformatec/devise/wiki/How-to:-Use-a-custom-email-validator-with-Devise) 45 | * [Notify users via email when their passwords change](https://github.com/plataformatec/devise/wiki/Notify-users-via-email-when-their-passwords-change) 46 | * [Customize minimum password length](https://github.com/plataformatec/devise/wiki/Customize-minimum-password-length) 47 | 48 | ## View/Content Customization 49 | 50 | * [Create custom layouts](https://github.com/plataformatec/devise/wiki/How-To:-Create-custom-layouts) 51 | * [Custom mailer](https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer) 52 | * [I18n](https://github.com/plataformatec/devise/wiki/I18n) 53 | * [Set :host and :port for all devise mailer urls](https://github.com/plataformatec/devise/wiki/How-To:-Set-:host-and-:port-for-all-devise-mailer-urls) 54 | * [Override devise_error_messages! for use in views](https://github.com/plataformatec/devise/wiki/Override-devise_error_messages!-for-views) 55 | * [Integrate I18n Flash Messages with Devise and Bootstrap](https://github.com/plataformatec/devise/wiki/How-To:-Integrate-I18n-Flash-Messages-with-Devise-and-Bootstrap) 56 | * [I18n Messages for Scoped Resources](https://github.com/plataformatec/devise/wiki/How-To:I18n-Message-for-Scoped-Resources) 57 | * [Add sign_in, sign_out, and sign_up links to your layout template](https://github.com/plataformatec/devise/wiki/How-To:-Add-sign_in,-sign_out,-and-sign_up-links-to-your-layout-template) 58 | 59 | ## Custom Authentication Methods 60 | 61 | * [Allow users to sign in with something other than their email address](https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-with-something-other-than-their-email-address) 62 | * [Authenticate via LDAP](https://github.com/plataformatec/devise/wiki/How-To:-Authenticate-via-LDAP) 63 | * [Create a guest user](https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user) 64 | * [Email-only sign-up](https://github.com/plataformatec/devise/wiki/How-To:-Email-only-sign-up) 65 | * [Edit an account without providing a password](https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password) 66 | * [HTTP Authentication](https://github.com/plataformatec/devise/wiki/How-To:-Use-HTTP-Basic-Authentication) 67 | * [HTTP Auth Basic](https://github.com/plataformatec/devise/wiki/How-To:-Use-HTTP-Auth-Basic-with-Devise) 68 | * [Recaptcha](https://github.com/plataformatec/devise/wiki/How-To:-Use-Recaptcha-with-Devise) 69 | * [Remote authentication with Devise](https://github.com/plataformatec/devise/wiki/How-to:-Remote-authentication-with-Devise) 70 | * [Set up devise as a single user system](https://github.com/plataformatec/devise/wiki/How-To:-Set-up-devise-as-a-single-user-system) 71 | * [Sign in using either a username or email address](https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address) 72 | * [Simple Token Authentication Example](https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example) 73 | * [Use case insensitive emails](https://github.com/plataformatec/devise/wiki/How-To:-Use-case-insensitive-emails) 74 | * [Use SSL (HTTPS)](https://github.com/plataformatec/devise/wiki/How-To:-Use-SSL-%28HTTPS%29) 75 | * [Use subdomains](https://github.com/plataformatec/devise/wiki/How-To:-Use-subdomains) 76 | * [AWS Cognito Federated Identity Authentication Example](http://c.mirifique.ch/2018/04/09/rails-devise-authenticating-using-aws-cognito-identity) 77 | 78 | ### OmniAuth 79 | 80 | * [OmniAuth: Overview](https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview) 81 | * [OmniAuth: Testing](https://github.com/plataformatec/devise/wiki/OmniAuth:--Testing) 82 | * [Omniauthable, sign out action and rememberable](https://github.com/plataformatec/devise/wiki/Omniauthable,-sign-out-action-and-rememberable) 83 | 84 | 85 | ## Testing 86 | 87 | * [Capybara](https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara) 88 | * [Controller tests with Rails (and RSpec)](https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-%28and-RSpec%29) 89 | * [Cucumber](https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Cucumber) 90 | * [OmniAuth: Testing](https://github.com/plataformatec/devise/wiki/OmniAuth:--Testing) 91 | * [Rspec with devise and machinist](https://github.com/plataformatec/devise/wiki/How-To:-Rspec-with-devise-and-machinist) 92 | * [Speed up your unit tests](https://github.com/plataformatec/devise/wiki/Speed-up-your-unit-tests) 93 | * [Stub authentication in controller specs](https://github.com/plataformatec/devise/wiki/How-To:-Stub-authentication-in-controller-specs) 94 | 95 | 96 | ## Privileges/Authorization 97 | 98 | * [Add an Admin role](https://github.com/plataformatec/devise/wiki/How-To:-Add-an-Admin-role) 99 | * [Add a default role to a User](https://github.com/plataformatec/devise/wiki/How-To:-Add-a-default-role-to-a-User) 100 | * [Create a guest user](https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user) 101 | * [Integrate with CanCan for roles management](https://github.com/plataformatec/devise/wiki/How-To:-Integrate-with-CanCan-for-roles-management) 102 | * [Manage Users with an Admin Role (CanCan method)](https://github.com/plataformatec/devise/wiki/How-To:-Manage-Users-with-an-Admin-Role-(CanCan-method)) 103 | * [Require admin to activate account before sign_in](https://github.com/plataformatec/devise/wiki/How-To:-Require-admin-to-activate-account-before-sign_in) 104 | * [Sign in as another user if you are an admin](https://github.com/plataformatec/devise/wiki/How-To:-Sign-in-as-another-user-if-you-are-an-admin) 105 | * [Turn off trackable for admin users](https://github.com/plataformatec/devise/wiki/How-To:-Turn-off-trackable-for-admin-users) 106 | 107 | ## Special Configurations 108 | 109 | * [Add :confirmable to Users](https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users) 110 | * [Add :lockable to Users](https://github.com/plataformatec/devise/wiki/How-To:-Add-:lockable-to-Users) 111 | * [Create a custom encryptor](https://github.com/plataformatec/devise/wiki/How-To:-Create-a-custom-encryptor) 112 | * [Create Haml and Slim Views](https://github.com/plataformatec/devise/wiki/How-To:-Create-Haml-and-Slim-Views) 113 | * [Configure a master password](https://github.com/plataformatec/devise/wiki/How-To:-Configure-a-master-password) 114 | * [Customize user account status validation when logging in](https://github.com/plataformatec/devise/wiki/How-To:-Customize-user-account-status-validation-when-logging-in) 115 | * [Disable user from destroying their account](https://github.com/plataformatec/devise/wiki/How-To:-Disable-user-from-destroying-their-account) 116 | * [Disallow previously used passwords](https://github.com/plataformatec/devise/wiki/How-To:-Disallow-previously-used-passwords) 117 | * [Dynamic user registration timeout](https://github.com/plataformatec/devise/wiki/How-To:-Add-timeout_in-value-dynamically) 118 | * [Embed users in your account model with Mongoid](https://github.com/plataformatec/devise/wiki/How-To:-Embed-users-in-your-account-model-with-Mongoid) 119 | * [Protect Resque Web with Devise](https://github.com/plataformatec/devise/wiki/How-To:-Protect-Resque-Web-with-Devise) 120 | * [Send emails from subdomains](https://github.com/plataformatec/devise/wiki/How-To:-Send-emails-from-subdomains) 121 | * [Send emails in background (Resque, Sidekiq and Delayed::Job)](https://github.com/plataformatec/devise/wiki/How-To%3A-Send-devise-emails-in-background-%28Resque%2C-Sidekiq-and-Delayed%3A%3AJob%29) 122 | * [Using paranoid mode, avoid user enumeration on registerable](https://github.com/plataformatec/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable) 123 | * [Use Devise Inside a Mountable Engine](https://github.com/plataformatec/devise/wiki/How-To:-Use-devise-inside-a-mountable-engine) 124 | 125 | ## Elsewhere in your App 126 | 127 | * [Add sign_in, sign_out, and sign_up links to your layout template](https://github.com/plataformatec/devise/wiki/How-To:-Add-sign_in,-sign_out,-and-sign_up-links-to-your-layout-template) 128 | * [Display a custom sign_in form anywhere in your app](https://github.com/plataformatec/devise/wiki/How-To:-Display-a-custom-sign_in-form-anywhere-in-your-app) 129 | * [Sign in from a controller](https://github.com/plataformatec/devise/wiki/How-To:-Sign-in-from-a-controller) 130 | * [Use Devise generated method and filters for controllers](https://github.com/plataformatec/devise/wiki/How-To:-Use-Devise-generated-method-and-filters-for-controllers) 131 | * [Find a user when you have their credentials](https://github.com/plataformatec/devise/wiki/How-To:-Find-a-user-when-you-have-their-credentials) 132 | * [Make Devise work with other formats like mobile, iPhone and iPad (Rails specific)](https://github.com/plataformatec/devise/wiki/How-To:-Make-Devise-work-with-other-formats-like-mobile,-iPhone-and-iPad---Rails-specific) 133 | * [Manage users through a CRUD interface](https://github.com/plataformatec/devise/wiki/How-To:-Manage-users-through-a-CRUD-interface) 134 | * [Mass password reset and email notification](https://github.com/plataformatec/devise/wiki/How-To:-Mass-password-reset-and-email-notification) 135 | 136 | ## JavaScript 137 | 138 | * [Use with BackboneJS models](https://github.com/plataformatec/devise/wiki/How-To:-Use-with-BackboneJS-models) 139 | 140 | ## Migrating from other authentication plugins 141 | * [Migrate from restful_authentication to Devise](https://github.com/plataformatec/devise/wiki/How-To:-Migrate-from-restful_authentication-to-Devise) 142 | * [Add devise required columns to an existing users table](https://github.com/plataformatec/devise/wiki/How-To:-change-an-already-existing-table-to-add-devise-required-columns) -------------------------------------------------------------------------------- /docs/devise/i18n.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: i18n 3 | title: I18n 4 | --- 5 | 6 | Devise uses flash messages with I18n, in conjunction with the flash keys :notice and :alert. To customize your app, you can set up your locale file: 7 | 8 | ```yaml 9 | en: 10 | devise: 11 | sessions: 12 | signed_in: 'Signed in successfully.' 13 | ``` 14 | 15 | You can also create distinct messages based on the resource you've configured using the singular name given in routes: 16 | 17 | ```yaml 18 | en: 19 | devise: 20 | sessions: 21 | user: 22 | signed_in: 'Welcome user, you are signed in.' 23 | admin: 24 | signed_in: 'Hello admin!' 25 | ``` 26 | 27 | The Devise mailer uses a similar pattern to create subject messages: 28 | 29 | ```yaml 30 | en: 31 | devise: 32 | mailer: 33 | confirmation_instructions: 34 | subject: 'Hello everybody!' 35 | user_subject: 'Hello User! Please confirm your email' 36 | reset_password_instructions: 37 | subject: 'Reset instructions' 38 | ``` 39 | 40 | Take a look at our locale file to check all available messages. You may also be interested in one of the many translations that are available on our wiki: 41 | 42 | https://github.com/plataformatec/devise/wiki/I18n 43 | 44 | Caution: Devise Controllers inherit from ApplicationController. If your app uses multiple locales, you should be sure to set I18n.locale in ApplicationController. -------------------------------------------------------------------------------- /docs/devise/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: installation 3 | title: Installation 4 | --- 5 | Devise 4.0 works with Rails 4.1 onwards. Add the following line to your Gemfile: 6 | 7 | ```ruby 8 | gem 'devise' 9 | ``` 10 | 11 | Then run `bundle install` 12 | 13 | Next, you need to run the generator: 14 | 15 | ```console 16 | $ rails generate devise:install 17 | ``` 18 | 19 | At this point, a number of instructions will appear in the console. Among these instructions, you'll need to set up the default URL options for the Devise mailer in each environment. Here is a possible configuration for `config/environments/development.rb`: 20 | 21 | ```ruby 22 | config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } 23 | ``` 24 | 25 | The generator will install an initializer which describes ALL of Devise's configuration options. It is *imperative* that you take a look at it. When you are done, you are ready to add Devise to any of your models using the generator. 26 | 27 | 28 | In the following command you will replace `MODEL` with the class name used for the application’s users (it’s frequently `User` but could also be `Admin`). This will create a model (if one does not exist) and configure it with the default Devise modules. The generator also configures your `config/routes.rb` file to point to the Devise controller. 29 | 30 | ```console 31 | $ rails generate devise MODEL 32 | ``` 33 | 34 | Next, check the MODEL for any additional configuration options you might want to add, such as confirmable or lockable. If you add an option, be sure to inspect the migration file (created by the generator if your ORM supports them) and uncomment the appropriate section. For example, if you add the confirmable option in the model, you'll need to uncomment the Confirmable section in the migration. 35 | 36 | Then run `rails db:migrate` 37 | 38 | You should restart your application after changing Devise's configuration options (this includes stopping spring). Otherwise, you will run into strange errors, for example, users being unable to login and route helpers being undefined. 39 | -------------------------------------------------------------------------------- /docs/devise/omniauth.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: omniauth 3 | title: OmniAuth 4 | --- 5 | > Since version 1.2, Devise supports integration with [OmniAuth](http://github.com/intridea/omniauth). This wiki page will cover the basics to have this integration working using an OAuth provider as example. 6 | 7 | > Since version 1.5, Devise supports OmniAuth 1.0 forward which will be the version covered by this tutorial. 8 | 9 | Devise comes with OmniAuth support out of the box to authenticate with other providers. To use it, simply specify your OmniAuth configuration in `config/initializers/devise.rb`: 10 | 11 | ```ruby 12 | config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' 13 | ``` 14 | 15 | ## Before you start 16 | 17 | Remember that `config.omniauth` adds omniauth provider middleware to your application. This means you should **not** add this provider middleware again in `config/initializers/omniauth.rb` as they'll clash with each other and result in always-failing authentication. 18 | 19 | ## Facebook example 20 | 21 | The first step then is to add an OmniAuth gem to your application. This can be done in our `Gemfile`: 22 | 23 | ```ruby 24 | gem 'omniauth-facebook' 25 | ``` 26 | 27 | Here we'll use Facebook as an example, but you are free to use whatever and as many OmniAuth gems as you'd like. Generally, the gem name is "omniauth-provider" where provider can be "facebook" or "twitter", for example. For a full list of these providers, please check [OmniAuth's list of strategies](https://github.com/intridea/omniauth/wiki/List-of-Strategies). 28 | 29 | Next up, you should add the columns "provider" (string) and "uid" (string) to your User model. 30 | 31 | ```rails 32 | rails g migration AddOmniauthToUsers provider:string uid:string 33 | rake db:migrate 34 | ``` 35 | 36 | Next, you need to declare the provider in your `config/initializers/devise.rb`: 37 | 38 | ```ruby 39 | config.omniauth :facebook, "APP_ID", "APP_SECRET" 40 | ``` 41 | 42 | If you are seeing something like _Could not authenticate you from Facebook because “Invalid credentials”_ 43 | you may need to add `token_params: { parse: :json }` to your config, i.e.: 44 | 45 | ```ruby 46 | config.omniauth :facebook, "APP_ID", "APP_SECRET", token_params: { parse: :json } 47 | ``` 48 | 49 | To alter the permissions or scopes requested, check the [omniauth-facebook](https://github.com/mkdynamic/omniauth-facebook) gem's README. 50 | 51 | After configuring your strategy, you need to make your model (e.g. `app/models/user.rb`) omniauthable: 52 | 53 | ```ruby 54 | devise :omniauthable, omniauth_providers: %i[facebook] 55 | ``` 56 | 57 | >**Note**: If you're running a rails server, you'll need to restart it to recognize the change in the `Devise` initializer or adding `:omniauthable` to your `User` model will create an error. 58 | 59 | Currently, Devise allows only one model to be omniauthable. If you want to use `OmniAuth` with multiple models, check out [OmniAuth with multiple models](https://github.com/plataformatec/devise/wiki/OmniAuth-with-multiple-models). 60 | 61 | After making a model named `User` omniauthable and if `devise_for :users` was already added to your `config/routes.rb`, Devise will create the following url methods: 62 | 63 | * user_{provider}_omniauth_authorize_path 64 | * user_{provider}_omniauth_callback_path 65 | 66 | Note that Devise does not create `*_url` methods. While you will never use the callback helper above directly, you only need to add the first one to your layouts in order to provide facebook authentication: 67 | 68 | ```ruby 69 | <%= link_to "Sign in with Facebook", user_facebook_omniauth_authorize_path %> 70 | ``` 71 | 72 | >**Note**: The `{provider}` in the above `*_path` methods matches the symbol of the provider passed to Devise's config block. Please check that `omniauth-*` gem's **README** to know which symbol you should use. 73 | 74 | By clicking on the above link, the user will be redirected to `Facebook`. (If this link doesn't exist, try restarting the server.) After inserting their credentials, they will be redirected back to your application's callback method. To implement a callback, the first step is to go back to our `config/routes.rb` file and tell Devise in which controller we will implement Omniauth callbacks: 75 | 76 | ```ruby 77 | devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } 78 | ``` 79 | 80 | Now we just add the file `app/controllers/users/omniauth_callbacks_controller.rb`: 81 | 82 | ```ruby 83 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 84 | end 85 | ``` 86 | 87 | The callback should be implemented as an action with the same name as the provider. Here is an example action for our facebook provider that we could add to our controller: 88 | 89 | ```ruby 90 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 91 | def facebook 92 | # You need to implement the method below in your model (e.g. app/models/user.rb) 93 | @user = User.from_omniauth(request.env["omniauth.auth"]) 94 | 95 | if @user.persisted? 96 | sign_in_and_redirect @user, event: :authentication #this will throw if @user is not activated 97 | set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format? 98 | else 99 | session["devise.facebook_data"] = request.env["omniauth.auth"] 100 | redirect_to new_user_registration_url 101 | end 102 | end 103 | 104 | def failure 105 | redirect_to root_path 106 | end 107 | end 108 | ``` 109 | 110 | This action has a few aspects worth describing: 111 | 112 | 1. All information retrieved from Facebook by OmniAuth is available as a hash at `request.env["omniauth.auth"]`. Check the [OmniAuth docs](https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema) and each [omniauth-facebook](https://github.com/mkdynamic/omniauth-facebook#auth-hash) gem's README to know which information is being returned. 113 | 114 | 2. When a valid user is found, they can be signed in with one of two Devise methods: `sign_in` or `sign_in_and_redirect`. Passing `:event => :authentication` is optional. You should only do so if you wish to use [Warden callbacks](http://stackoverflow.com/a/13389324/1160916). 115 | 116 | 3. A flash message can also be set using one of Devise's default messages, but that is up to you. 117 | 118 | 4. In case the user is not persisted, we store the OmniAuth data in the session. Notice we store this data using "devise." as key namespace. This is useful because Devise removes all the data starting with "devise." from the session whenever a user signs in, so we get automatic session clean up. At the end, we redirect the user back to our registration form. 119 | 120 | After the controller is defined, we need to implement the `from_omniauth` method in our model (e.g. `app/models/user.rb`): 121 | 122 | ```ruby 123 | def self.from_omniauth(auth) 124 | where(provider: auth.provider, uid: auth.uid).first_or_create do |user| 125 | user.email = auth.info.email 126 | user.password = Devise.friendly_token[0, 20] 127 | user.name = auth.info.name # assuming the user model has a name 128 | user.image = auth.info.image # assuming the user model has an image 129 | # If you are using confirmable and the provider(s) you use validate emails, 130 | # uncomment the line below to skip the confirmation emails. 131 | # user.skip_confirmation! 132 | end 133 | end 134 | ``` 135 | 136 | This method tries to find an existing user by the `provider` and `uid` fields. If no user is found, a new one is created with a random password and some extra information. 137 | Note that the [`first_or_create` method](http://apidock.com/rails/v3.2.1/ActiveRecord/Relation/first_or_create) automatically sets the `provider` and `uid` fields when creating a new user. The [`first_or_create!` method](http://apidock.com/rails/v3.2.1/ActiveRecord/Relation/first_or_create!) operates similarly, except that it will raise an Exception if the user record fails validation. 138 | 139 | Notice that Devise's `RegistrationsController` by default calls `User.new_with_session` before building a resource. This means that, if we need to copy data from session whenever a user is initialized before sign up, we just need to implement `new_with_session` in our model. Here is an example that copies the facebook email if available: 140 | 141 | ```ruby 142 | class User < ApplicationRecord 143 | def self.new_with_session(params, session) 144 | super.tap do |user| 145 | if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"] 146 | user.email = data["email"] if user.email.blank? 147 | end 148 | end 149 | end 150 | end 151 | ``` 152 | 153 | Finally, if you want to allow your users to cancel sign up with Facebook, you can redirect them to `cancel_user_registration_path`. This will remove all session data starting with `devise.` and the `new_with_session` hook above will no longer be called. 154 | 155 | ### Logout links 156 | 157 | 158 | ```ruby 159 | # config/routes.rb 160 | devise_scope :user do 161 | delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session 162 | end 163 | ``` 164 | 165 | And that is all you need! After you get your integration working, it's time to write some integration tests: 166 | 167 | [https://github.com/intridea/omniauth/wiki/Integration-Testing](https://github.com/intridea/omniauth/wiki/Integration-Testing) 168 | 169 | ## Using OmniAuth without other authentications 170 | 171 | If you are using **ONLY** omniauth authentication, you need to define a route named `new_user_session` (if not defined, root will be used). Below is an example of such routes (you don't need to include it if you are also using database or other authentication with omniauth): 172 | 173 | ```ruby 174 | devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } 175 | 176 | devise_scope :user do 177 | get 'sign_in', :to => 'devise/sessions#new', :as => :new_user_session 178 | get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session 179 | end 180 | ``` 181 | 182 | In the example above, the sessions controller doesn't need to do anything special. For example, showing a link to the provider authentication will suffice. 183 | 184 | > **Note**: If your Devise configuration specifies `sign_out_via = :delete`, you may need to adjust your sign_out route to match an incoming DELETE request instead. 185 | 186 | Also, if you are not using `:database_authenticatable` you have to define the helper method `new_session_path(scope)` so it can correctly redirect in case of failure: 187 | 188 | ```ruby 189 | class ApplicationController < ActionController::Base 190 | # ... 191 | def new_session_path(scope) 192 | new_user_session_path 193 | end 194 | end 195 | ``` 196 | 197 | ## Troubleshooting 198 | 199 | ### User didn't allow email permissions 200 | 201 | In the new Facebook login dialog the user can decline to provide email address. 202 | Devise usually requires email to register. A quick and dirty solution to this problem is to re-request the email if it wasn't found: 203 | 204 | ```ruby 205 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 206 | def facebook 207 | if request.env["omniauth.auth"].info.email.blank? 208 | redirect_to "/users/auth/facebook?auth_type=rerequest&scope=email" 209 | return # be sure to include an return if there is code after this otherwise it will be executed 210 | end 211 | end 212 | end 213 | ``` 214 | 215 | ### Facebook returning nulled email 216 | 217 | Since July 8th 2015 Facebook changed to api v2.4, you need to add extra `info_fields` to get email field. 218 | ```ruby 219 | config.omniauth :facebook, "APP_ID", "APP_SECRET", scope: 'email', info_fields: 'email,name' 220 | ``` 221 | [found solution from here by @techmonster](https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application) 222 | 223 | If this solution doesn't work for you. Please, try to use fields instead of info_fields. 224 | 225 | ### Extra config 226 | 227 | Facebook OAuth gem uses the API version `V2.6` by default. 228 | This might not work for you, as your app might be configured to use a different version of GraphAPI. 229 | So you need to make sure your web-app is making the correct call. 230 | You need to add extra option `client_options`. See an example: 231 | 232 | ```ruby 233 | config.omniauth :facebook, ENV['FB_APP_ID'], ENV['FB_APP_SECRET'], 234 | scope: 'public_profile,email', 235 | info_fields: 'email,first_name,last_name,gender,birthday,location,picture', 236 | client_options: { 237 | site: 'https://graph.facebook.com/v2.11', 238 | authorize_url: "https://www.facebook.com/v2.11/dialog/oauth" 239 | } 240 | ``` 241 | 242 | ### OpenSSL 243 | 244 | If you run into an OpenSSL error like this: 245 | 246 | ```ruby 247 | OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed): 248 | ``` 249 | 250 | Then you need to explicitly tell OmniAuth where to locate your CA certificate file. 251 | Either use the [certified gem](https://github.com/stevegraham/certified) or this method (depending on the OS you are running on): 252 | 253 | ```ruby 254 | config.omniauth :facebook, "APP_ID", "APP_SECRET", 255 | client_options: { ssl: { ca_path: '/etc/ssl/certs' } } 256 | ``` 257 | 258 | On Heroku, the CA file is located at `/usr/lib/ssl/certs/ca-certificates.crt` 259 | 260 | On Engine Yard Cloud servers, the CA file is located at `/etc/ssl/certs/ca-certificates.crt`. 261 | 262 | These certificates can be set using the `:ca_file` key: 263 | 264 | ```ruby 265 | config.omniauth :facebook, "APP_ID", "APP_SECRET", 266 | client_options: { ssl: { ca_file: '/usr/lib/ssl/certs/ca-certificates.crt' } } 267 | ``` 268 | 269 | If you are using a strategy that uses the OAuth gem eg [omniauth-oauth](https://github.com/intridea/omniauth-oauth) then specify the certificate file this way: 270 | 271 | ```ruby 272 | config.omniauth :facebook, "APP_ID", "APP_SECRET", 273 | client_options: { ca_file: '/usr/lib/ssl/certs/ca-certificates.crt' } 274 | ``` 275 | 276 | On macOS, for development only, it may be easiest just to disable certificate verification because the certificates are stored in the keychain, not the file system: 277 | 278 | ```ruby 279 | require "omniauth-facebook" 280 | config.omniauth :facebook, "APP_ID", "APP_SECRET", client_options: { ssl: { verify: !Rails.env.development? } } 281 | ``` 282 | 283 | A deeper discussion of this error can be found here: https://github.com/intridea/omniauth/issues/260 284 | 285 | ### Cannot load strategy class 286 | 287 | If for some reason Devise cannot load your strategy class, you can set it explicitly with the `:strategy_class` option: 288 | 289 | ```ruby 290 | config.omniauth :facebook, "APP_ID", "APP_SECRET", :strategy_class => OmniAuth::Strategies::Facebook 291 | ``` 292 | -------------------------------------------------------------------------------- /docs/devise/other-orms.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: other-orms 3 | title: Other ORMs 4 | --- 5 | 6 | Since Devise support both Mongoid and ActiveRecord, we rely on this variable to run specific code for each ORM. 7 | The default value of `DEVISE_ORM` is `active_record`. To run the tests for mongoid, you can pass `mongoid`: 8 | ``` 9 | DEVISE_ORM=mongoid bin/test 10 | 11 | ==> Devise.orm = :mongoid 12 | ``` 13 | When running the tests for Mongoid, you will need to have a MongoDB server (version 2.0 or newer) running on your system. 14 | 15 | Please note that the command output will show the variable value being used. -------------------------------------------------------------------------------- /docs/devise/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: overview 3 | title: Overview 4 | --- 5 | ![Devise Logo](https://raw.github.com/plataformatec/devise/master/devise.png) 6 | 7 | By [Plataformatec](http://plataformatec.com.br/). 8 | 9 | Devise is a flexible authentication solution for Rails based on Warden. It: 10 | 11 | * Is Rack based; 12 | * Is a complete MVC solution based on Rails engines; 13 | * Allows you to have multiple models signed in at the same time; 14 | * Is based on a modularity concept: use only what you really need. 15 | 16 | ## Modules 17 | 18 | It's composed of 10 modules: 19 | 20 | * [Database Authenticatable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/DatabaseAuthenticatable): hashes and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication. 21 | * [Omniauthable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Omniauthable): adds OmniAuth (https://github.com/omniauth/omniauth) support. 22 | * [Confirmable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in. 23 | * [Recoverable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Recoverable): resets the user password and sends reset instructions. 24 | * [Registerable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Registerable): handles signing up users through a registration process, also allowing them to edit and destroy their account. 25 | * [Rememberable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Rememberable): manages generating and clearing a token for remembering the user from a saved cookie. 26 | * [Trackable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Trackable): tracks sign in count, timestamps and IP address. 27 | * [Timeoutable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Timeoutable): expires sessions that have not been active in a specified period of time. 28 | * [Validatable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations. 29 | * [Lockable](http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period. 30 | 31 | ## RDocs (API) 32 | 33 | You can view the Devise documentation in RDoc format here: 34 | 35 | http://rubydoc.info/github/plataformatec/devise/master/frames 36 | 37 | If you need to use Devise with previous versions of Rails, you can always run "gem server" from the command line after you install the gem to access the old documentation. 38 | 39 | 40 | ## StackOverflow and Mailing List 41 | 42 | If you have any questions, comments, or concerns, please use StackOverflow instead of the GitHub issue tracker: 43 | 44 | http://stackoverflow.com/questions/tagged/devise 45 | 46 | The deprecated mailing list can still be read on 47 | 48 | https://groups.google.com/group/plataformatec-devise 49 | 50 | 51 | ## Running tests 52 | Devise uses [Mini Test](https://github.com/seattlerb/minitest) as test framework. 53 | 54 | * Running all tests: 55 | ```bash 56 | bin/test 57 | ``` 58 | 59 | * Running tests for an specific file: 60 | ```bash 61 | bin/test test/models/trackable_test.rb 62 | ``` 63 | 64 | * Running a specific test given a regex: 65 | ```bash 66 | bin/test test/models/trackable_test.rb:16 67 | ``` 68 | 69 | ## Contributors 70 | 71 | We have a long list of valued contributors. Check them all at: 72 | 73 | https://github.com/plataformatec/devise/graphs/contributors 74 | 75 | ## License 76 | 77 | MIT License. Copyright 2009-2018 Plataformatec. http://plataformatec.com.br 78 | 79 | You are not granted rights or licenses to the trademarks of Plataformatec, including without limitation the Devise name or logo. -------------------------------------------------------------------------------- /docs/devise/password-reset-tokens-and-rails-logs.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: password-reset-tokens-and-rails-logs 3 | title: Password reset tokens and Rails logs 4 | --- 5 | 6 | If you enable the [Recoverable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Recoverable) module, note that a stolen password reset token could give an attacker access to your application. Devise takes effort to generate random, secure tokens, and stores only token digests in the database, never plaintext. However the default logging behavior in Rails can cause plaintext tokens to leak into log files: 7 | 8 | 1. Action Mailer logs the entire contents of all outgoing emails to the DEBUG level. Password reset tokens delivered to users in email will be leaked. 9 | 2. Active Job logs all arguments to every enqueued job at the INFO level. If you configure Devise to use `deliver_later` to send password reset emails, password reset tokens will be leaked. 10 | 11 | Rails sets the production logger level to DEBUG by default. Consider changing your production logger level to WARN if you wish to prevent tokens from being leaked into your logs. In `config/environments/production.rb`: 12 | 13 | ```ruby 14 | config.log_level = :warn 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/devise/rails-api-mode.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: rails-api-mode 3 | title: Rails API mode 4 | --- 5 | 6 | Rails 5+ has a built-in [API Mode](https://edgeguides.rubyonrails.org/api_app.html) which optimizes Rails for use as an API (only). One of the side effects is that it changes the order of the middleware stack, and this can cause problems for `Devise::Test::IntegrationHelpers`. This problem usually surfaces as an ```undefined method `[]=' for nil:NilClass``` error when using integration test helpers, such as `#sign_in`. The solution is simply to reorder the middlewares by adding the following to test.rb: 7 | 8 | ```ruby 9 | Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies 10 | Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore 11 | ``` 12 | 13 | For a deeper understanding of this, review [this issue](https://github.com/plataformatec/devise/issues/4696). -------------------------------------------------------------------------------- /docs/devise/starting_with_rails.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: starting-with-rails 3 | title: Starting with rails? 4 | --- 5 | 6 | If you are building your first Rails application, we recommend you *do not* use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch. Today, we have three resources that should help you get started: 7 | 8 | * Michael Hartl's online book: https://www.railstutorial.org/book/modeling_users 9 | * Ryan Bates' Railscast: http://railscasts.com/episodes/250-authentication-from-scratch 10 | * Codecademy's Ruby on Rails: Authentication and Authorization: https://www.codecademy.com/learn/rails-auth 11 | 12 | Once you have solidified your understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. :smiley: -------------------------------------------------------------------------------- /docs/devise/strong-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: strong-parameters 3 | title: Strong Parameters 4 | --- 5 | 6 | > The Parameter Sanitizer API has changed for Devise 4. 7 | > *For previous Devise versions see https://github.com/plataformatec/devise/tree/3-stable#strong-parameters* 8 | 9 | When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing Devise to handle this concern at the controller as well. 10 | 11 | There are just three actions in Devise that allow any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and default permitted parameters are: 12 | 13 | * `sign_in` (`Devise::SessionsController#create`) - Permits only the authentication keys (like `email`) 14 | * `sign_up` (`Devise::RegistrationsController#create`) - Permits authentication keys plus `password` and `password_confirmation` 15 | * `account_update` (`Devise::RegistrationsController#update`) - Permits authentication keys plus `password`, `password_confirmation` and `current_password` 16 | 17 | In case you want to permit additional parameters (the lazy way™), you can do so using a simple before filter in your `ApplicationController`: 18 | 19 | ```ruby 20 | class ApplicationController < ActionController::Base 21 | before_action :configure_permitted_parameters, if: :devise_controller? 22 | 23 | protected 24 | 25 | def configure_permitted_parameters 26 | devise_parameter_sanitizer.permit(:sign_up, keys: [:username]) 27 | end 28 | end 29 | ``` 30 | 31 | The above works for any additional fields where the parameters are simple scalar types. If you have nested attributes (say you're using `accepts_nested_attributes_for`), then you will need to tell devise about those nestings and types: 32 | 33 | ```ruby 34 | class ApplicationController < ActionController::Base 35 | before_action :configure_permitted_parameters, if: :devise_controller? 36 | 37 | protected 38 | 39 | def configure_permitted_parameters 40 | devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, address_attributes: [:country, :state, :city, :area, :postal_code]]) 41 | end 42 | end 43 | ``` 44 | 45 | Devise allows you to completely change Devise defaults or invoke custom behaviour by passing a block: 46 | 47 | To permit simple scalar values for username and email, use this 48 | 49 | ```ruby 50 | def configure_permitted_parameters 51 | devise_parameter_sanitizer.permit(:sign_in) do |user_params| 52 | user_params.permit(:username, :email) 53 | end 54 | end 55 | ``` 56 | 57 | If you have some checkboxes that express the roles a user may take on registration, the browser will send those selected checkboxes as an array. An array is not one of Strong Parameters' permitted scalars, so we need to configure Devise in the following way: 58 | 59 | ```ruby 60 | def configure_permitted_parameters 61 | devise_parameter_sanitizer.permit(:sign_up) do |user_params| 62 | user_params.permit({ roles: [] }, :email, :password, :password_confirmation) 63 | end 64 | end 65 | ``` 66 | For the list of permitted scalars, and how to declare permitted keys in nested hashes and arrays, see 67 | 68 | https://github.com/rails/strong_parameters#nested-parameters 69 | 70 | If you have multiple Devise models, you may want to set up a different parameter sanitizer per model. In this case, we recommend inheriting from `Devise::ParameterSanitizer` and adding your own logic: 71 | 72 | ```ruby 73 | class User::ParameterSanitizer < Devise::ParameterSanitizer 74 | def initialize(*) 75 | super 76 | permit(:sign_up, keys: [:username, :email]) 77 | end 78 | end 79 | ``` 80 | 81 | And then configure your controllers to use it: 82 | 83 | ```ruby 84 | class ApplicationController < ActionController::Base 85 | protected 86 | 87 | def devise_parameter_sanitizer 88 | if resource_class == User 89 | User::ParameterSanitizer.new(User, :user, params) 90 | else 91 | super # Use the default one 92 | end 93 | end 94 | end 95 | ``` 96 | 97 | The example above overrides the permitted parameters for the user to be both `:username` and `:email`. The non-lazy way to configure parameters would be by defining the before filter above in a custom controller. We detail how to configure and customize controllers in some sections below. -------------------------------------------------------------------------------- /docs/devise/test-helpers.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: test-helpers 3 | title: Test helpers 4 | --- 5 | 6 | Devise includes some test helpers for controller and integration tests. 7 | In order to use them, you need to include the respective module in your test 8 | cases/specs. 9 | 10 | ## Controller tests 11 | 12 | Controller tests require that you include `Devise::Test::ControllerHelpers` on 13 | your test case or its parent `ActionController::TestCase` superclass. 14 | For Rails 5, include `Devise::Test::IntegrationHelpers` instead, since the superclass 15 | for controller tests has been changed to ActionDispatch::IntegrationTest 16 | (for more details, see the [Integration tests](#integration-tests) section). 17 | 18 | ```ruby 19 | class PostsControllerTest < ActionController::TestCase 20 | include Devise::Test::ControllerHelpers 21 | end 22 | ``` 23 | 24 | If you're using RSpec, you can put the following inside a file named 25 | `spec/support/devise.rb` or in your `spec/spec_helper.rb` (or 26 | `spec/rails_helper.rb` if you are using `rspec-rails`): 27 | 28 | ```ruby 29 | RSpec.configure do |config| 30 | config.include Devise::Test::ControllerHelpers, type: :controller 31 | config.include Devise::Test::ControllerHelpers, type: :view 32 | end 33 | ``` 34 | 35 | Just be sure that this inclusion is made *after* the `require 'rspec/rails'` directive. 36 | 37 | Now you are ready to use the `sign_in` and `sign_out` methods on your controller 38 | tests: 39 | 40 | ```ruby 41 | sign_in @user 42 | sign_in @user, scope: :admin 43 | ``` 44 | 45 | If you are testing Devise internal controllers or a controller that inherits 46 | from Devise's, you need to tell Devise which mapping should be used before a 47 | request. This is necessary because Devise gets this information from the router, 48 | but since controller tests do not pass through the router, it needs to be stated 49 | explicitly. For example, if you are testing the user scope, simply use: 50 | 51 | ```ruby 52 | test 'GET new' do 53 | # Mimic the router behavior of setting the Devise scope through the env. 54 | @request.env['devise.mapping'] = Devise.mappings[:user] 55 | 56 | # Use the sign_in helper to sign in a fixture `User` record. 57 | sign_in users(:alice) 58 | 59 | get :new 60 | 61 | # assert something 62 | end 63 | ``` 64 | 65 | ## Integration tests 66 | 67 | Integration test helpers are available by including the 68 | `Devise::Test::IntegrationHelpers` module. 69 | 70 | ```ruby 71 | class PostsTests < ActionDispatch::IntegrationTest 72 | include Devise::Test::IntegrationHelpers 73 | end 74 | ``` 75 | 76 | Now you can use the following `sign_in` and `sign_out` methods in your integration 77 | tests: 78 | 79 | ```ruby 80 | sign_in users(:bob) 81 | sign_in users(:bob), scope: :admin 82 | 83 | sign_out :user 84 | ``` 85 | 86 | RSpec users can include the `IntegrationHelpers` module on their `:feature` specs. 87 | 88 | ```ruby 89 | RSpec.configure do |config| 90 | config.include Devise::Test::IntegrationHelpers, type: :feature 91 | end 92 | ``` 93 | 94 | Unlike controller tests, integration tests do not need to supply the 95 | `devise.mapping` `env` value, as the mapping can be inferred by the routes that 96 | are executed in your tests. 97 | 98 | You can read more about testing your Rails 3 - Rails 4 controllers with RSpec in the wiki: 99 | 100 | * https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-(and-RSpec) -------------------------------------------------------------------------------- /docs/rails/action_mailbox_basics.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: action-mailbox 3 | title: Action Mailbox Basics 4 | --- 5 | This guide provides you with all you need to get started in receiving 6 | emails to your application. 7 | 8 | After reading this guide, you will know: 9 | 10 | * How to receive email within a Rails application. 11 | * How to configure Action Mailbox. 12 | * How to generate and route emails to a mailbox. 13 | * How to test incoming emails. 14 | 15 | -------------------------------------------------------------------------------- 16 | 17 | Introduction 18 | ------------ 19 | 20 | Action Mailbox routes incoming emails to controller-like mailboxes for 21 | processing in Rails. It ships with ingresses for Mailgun, Mandrill, Postmark, 22 | and SendGrid. You can also handle inbound mails directly via the built-in Exim, 23 | Postfix, and Qmail ingresses. 24 | 25 | The inbound emails are turned into `InboundEmail` records using Active Record 26 | and feature lifecycle tracking, storage of the original email on cloud storage 27 | via Active Storage, and responsible data handling with 28 | on-by-default incineration. 29 | 30 | These inbound emails are routed asynchronously using Active Job to one or 31 | several dedicated mailboxes, which are capable of interacting directly 32 | with the rest of your domain model. 33 | 34 | ## Setup 35 | 36 | Install migrations needed for `InboundEmail` and ensure Active Storage is set up: 37 | 38 | ```bash 39 | $ rails action_mailbox:install 40 | $ rails db:migrate 41 | ``` 42 | 43 | ## Configuration 44 | 45 | ### Exim 46 | 47 | Tell Action Mailbox to accept emails from an SMTP relay: 48 | 49 | ```ruby 50 | # config/environments/production.rb 51 | config.action_mailbox.ingress = :relay 52 | ``` 53 | 54 | Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress. 55 | 56 | Use `rails credentials:edit` to add the password to your application's encrypted credentials under 57 | `action_mailbox.ingress_password`, where Action Mailbox will automatically find it: 58 | 59 | ```yaml 60 | action_mailbox: 61 | ingress_password: ... 62 | ``` 63 | 64 | Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable. 65 | 66 | Configure Exim to pipe inbound emails to `bin/rails action_mailbox:ingress:exim`, 67 | providing the `URL` of the relay ingress and the `INGRESS_PASSWORD` you 68 | previously generated. If your application lived at `https://example.com`, the 69 | full command would look like this: 70 | 71 | ```shell 72 | bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... 73 | ``` 74 | 75 | ### Mailgun 76 | 77 | Give Action Mailbox your 78 | [Mailgun API key](https://help.mailgun.com/hc/en-us/articles/203380100-Where-can-I-find-my-API-key-and-SMTP-credentials) 79 | so it can authenticate requests to the Mailgun ingress. 80 | 81 | Use `rails credentials:edit` to add your API key to your application's 82 | encrypted credentials under `action_mailbox.mailgun_api_key`, 83 | where Action Mailbox will automatically find it: 84 | 85 | ```yaml 86 | action_mailbox: 87 | mailgun_api_key: ... 88 | ``` 89 | 90 | Alternatively, provide your API key in the `MAILGUN_INGRESS_API_KEY` environment 91 | variable. 92 | 93 | Tell Action Mailbox to accept emails from Mailgun: 94 | 95 | ```ruby 96 | # config/environments/production.rb 97 | config.action_mailbox.ingress = :mailgun 98 | ``` 99 | 100 | [Configure Mailgun](https://documentation.mailgun.com/en/latest/user_manual.html#receiving-forwarding-and-storing-messages) 101 | to forward inbound emails to `/rails/action_mailbox/mailgun/inbound_emails/mime`. 102 | If your application lived at `https://example.com`, you would specify the 103 | fully-qualified URL `https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime`. 104 | 105 | ### Mandrill 106 | 107 | Give Action Mailbox your Mandrill API key so it can authenticate requests to 108 | the Mandrill ingress. 109 | 110 | Use `rails credentials:edit` to add your API key to your application's 111 | encrypted credentials under `action_mailbox.mandrill_api_key`, 112 | where Action Mailbox will automatically find it: 113 | 114 | ```yaml 115 | action_mailbox: 116 | mandrill_api_key: ... 117 | ``` 118 | 119 | Alternatively, provide your API key in the `MANDRILL_INGRESS_API_KEY` 120 | environment variable. 121 | 122 | Tell Action Mailbox to accept emails from Mandrill: 123 | 124 | ```ruby 125 | # config/environments/production.rb 126 | config.action_mailbox.ingress = :mandrill 127 | ``` 128 | 129 | [Configure Mandrill](https://mandrill.zendesk.com/hc/en-us/articles/205583197-Inbound-Email-Processing-Overview) 130 | to route inbound emails to `/rails/action_mailbox/mandrill/inbound_emails`. 131 | If your application lived at `https://example.com`, you would specify 132 | the fully-qualified URL `https://example.com/rails/action_mailbox/mandrill/inbound_emails`. 133 | 134 | ### Postfix 135 | 136 | Tell Action Mailbox to accept emails from an SMTP relay: 137 | 138 | ```ruby 139 | # config/environments/production.rb 140 | config.action_mailbox.ingress = :relay 141 | ``` 142 | 143 | Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress. 144 | 145 | Use `rails credentials:edit` to add the password to your application's encrypted credentials under 146 | `action_mailbox.ingress_password`, where Action Mailbox will automatically find it: 147 | 148 | ```yaml 149 | action_mailbox: 150 | ingress_password: ... 151 | ``` 152 | 153 | Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable. 154 | 155 | [Configure Postfix](https://serverfault.com/questions/258469/how-to-configure-postfix-to-pipe-all-incoming-email-to-a-script) 156 | to pipe inbound emails to `bin/rails action_mailbox:ingress:postfix`, providing 157 | the `URL` of the Postfix ingress and the `INGRESS_PASSWORD` you previously 158 | generated. If your application lived at `https://example.com`, the full command 159 | would look like this: 160 | 161 | ```shell 162 | $ bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... 163 | ``` 164 | 165 | ### Postmark 166 | 167 | Tell Action Mailbox to accept emails from Postmark: 168 | 169 | ```ruby 170 | # config/environments/production.rb 171 | config.action_mailbox.ingress = :postmark 172 | ``` 173 | 174 | Generate a strong password that Action Mailbox can use to authenticate 175 | requests to the Postmark ingress. 176 | 177 | Use `rails credentials:edit` to add the password to your application's 178 | encrypted credentials under `action_mailbox.ingress_password`, 179 | where Action Mailbox will automatically find it: 180 | 181 | ```yaml 182 | action_mailbox: 183 | ingress_password: ... 184 | ``` 185 | 186 | Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` 187 | environment variable. 188 | 189 | [Configure Postmark inbound webhook](https://postmarkapp.com/manual#configure-your-inbound-webhook-url) 190 | to forward inbound emails to `/rails/action_mailbox/postmark/inbound_emails` with the username `actionmailbox` 191 | and the password you previously generated. If your application lived at `https://example.com`, you would 192 | configure Postmark with the following fully-qualified URL: 193 | 194 | ``` 195 | https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound_emails 196 | ``` 197 | 198 | NOTE: When configuring your Postmark inbound webhook, be sure to check the box labeled **"Include raw email content in JSON payload"**. 199 | Action Mailbox needs the raw email content to work. 200 | 201 | ### Qmail 202 | 203 | Tell Action Mailbox to accept emails from an SMTP relay: 204 | 205 | ```ruby 206 | # config/environments/production.rb 207 | config.action_mailbox.ingress = :relay 208 | ``` 209 | 210 | Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress. 211 | 212 | Use `rails credentials:edit` to add the password to your application's encrypted credentials under 213 | `action_mailbox.ingress_password`, where Action Mailbox will automatically find it: 214 | 215 | ```yaml 216 | action_mailbox: 217 | ingress_password: ... 218 | ``` 219 | 220 | Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable. 221 | 222 | Configure Qmail to pipe inbound emails to `bin/rails action_mailbox:ingress:qmail`, 223 | providing the `URL` of the relay ingress and the `INGRESS_PASSWORD` you 224 | previously generated. If your application lived at `https://example.com`, the 225 | full command would look like this: 226 | 227 | ```shell 228 | bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... 229 | ``` 230 | 231 | ### SendGrid 232 | 233 | Tell Action Mailbox to accept emails from SendGrid: 234 | 235 | ```ruby 236 | # config/environments/production.rb 237 | config.action_mailbox.ingress = :sendgrid 238 | ``` 239 | 240 | Generate a strong password that Action Mailbox can use to authenticate 241 | requests to the SendGrid ingress. 242 | 243 | Use `rails credentials:edit` to add the password to your application's 244 | encrypted credentials under `action_mailbox.ingress_password`, 245 | where Action Mailbox will automatically find it: 246 | 247 | ```yaml 248 | action_mailbox: 249 | ingress_password: ... 250 | ``` 251 | 252 | Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` 253 | environment variable. 254 | 255 | [Configure SendGrid Inbound Parse](https://sendgrid.com/docs/for-developers/parsing-email/setting-up-the-inbound-parse-webhook/) 256 | to forward inbound emails to 257 | `/rails/action_mailbox/sendgrid/inbound_emails` with the username `actionmailbox` 258 | and the password you previously generated. If your application lived at `https://example.com`, 259 | you would configure SendGrid with the following URL: 260 | 261 | ``` 262 | https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails 263 | ``` 264 | 265 | NOTE: When configuring your SendGrid Inbound Parse webhook, be sure to check the box labeled **“Post the raw, full MIME message.”** Action Mailbox needs the raw MIME message to work. 266 | 267 | ## Examples 268 | 269 | Configure basic routing: 270 | 271 | ```ruby 272 | # app/mailboxes/application_mailbox.rb 273 | class ApplicationMailbox < ActionMailbox::Base 274 | routing /^save@/i => :forwards 275 | routing /@replies\./i => :replies 276 | end 277 | ``` 278 | 279 | Then set up a mailbox: 280 | 281 | ```ruby 282 | # Generate new mailbox 283 | $ bin/rails generate mailbox forwards 284 | ``` 285 | 286 | ```ruby 287 | # app/mailboxes/forwards_mailbox.rb 288 | class ForwardsMailbox < ApplicationMailbox 289 | # Callbacks specify prerequisites to processing 290 | before_processing :require_forward 291 | 292 | def process 293 | if forwarder.buckets.one? 294 | record_forward 295 | else 296 | stage_forward_and_request_more_details 297 | end 298 | end 299 | 300 | private 301 | def require_forward 302 | unless message.forward? 303 | # Use Action Mailers to bounce incoming emails back to sender – this halts processing 304 | bounce_with Forwards::BounceMailer.missing_forward( 305 | inbound_email, forwarder: forwarder 306 | ) 307 | end 308 | end 309 | 310 | def forwarder 311 | @forwarder ||= Person.where(email_address: mail.from) 312 | end 313 | 314 | def record_forward 315 | forwarder.buckets.first.record \ 316 | Forward.new forwarder: forwarder, subject: message.subject, content: mail.content 317 | end 318 | 319 | def stage_forward_and_request_more_details 320 | Forwards::RoutingMailer.choose_project(mail).deliver_now 321 | end 322 | end 323 | ``` 324 | 325 | ## Incineration of InboundEmails 326 | 327 | By default, an InboundEmail that has been successfully processed will be 328 | incinerated after 30 days. This ensures you're not holding on to people's data 329 | willy-nilly after they may have canceled their accounts or deleted their 330 | content. The intention is that after you've processed an email, you should have 331 | extracted all the data you needed and turned it into domain models and content 332 | on your side of the application. The InboundEmail simply stays in the system 333 | for the extra time to provide debugging and forensics options. 334 | 335 | The actual incineration is done via the `IncinerationJob` that's scheduled 336 | to run after `config.action_mailbox.incinerate_after` time. This value is 337 | by default set to `30.days`, but you can change it in your production.rb 338 | configuration. (Note that this far-future incineration scheduling relies on 339 | your job queue being able to hold jobs for that long.) 340 | 341 | ## Working with Action Mailbox in development 342 | 343 | It's helpful to be able to test incoming emails in development without actually 344 | sending and receiving real emails. To accomplish this, there's a conductor 345 | controller mounted at `/rails/conductor/action_mailbox/inbound_emails`, 346 | which gives you an index of all the InboundEmails in the system, their 347 | state of processing, and a form to create a new InboundEmail as well. 348 | 349 | ## Testing mailboxes 350 | 351 | Example: 352 | 353 | ```ruby 354 | class ForwardsMailboxTest < ActionMailbox::TestCase 355 | test "directly recording a client forward for a forwarder and forwardee corresponding to one project" do 356 | assert_difference -> { people(:david).buckets.first.recordings.count } do 357 | receive_inbound_email_from_mail \ 358 | to: 'save@example.com', 359 | from: people(:david).email_address, 360 | subject: "Fwd: Status update?", 361 | body: <<~BODY 362 | --- Begin forwarded message --- 363 | From: Frank Holland 364 | 365 | What's the status? 366 | BODY 367 | end 368 | 369 | recording = people(:david).buckets.first.recordings.last 370 | assert_equal people(:david), recording.creator 371 | assert_equal "Status update?", recording.forward.subject 372 | assert_match "What's the status?", recording.forward.content.to_s 373 | end 374 | end 375 | ``` 376 | -------------------------------------------------------------------------------- /docs/rails/action_text_overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: action-text 3 | title: Action Text Overview 4 | --- 5 | 6 | This guide provides you with all you need to get started in handling 7 | rich text content. 8 | 9 | After reading this guide, you will know: 10 | 11 | * How to configure Action Text. 12 | * How to handle rich text content. 13 | * How to style rich text content. 14 | 15 | -------------------------------------------------------------------------------- 16 | 17 | Introduction 18 | ------------ 19 | 20 | Action Text brings rich text content and editing to Rails. It includes 21 | the [Trix editor](https://trix-editor.org) that handles everything from formatting 22 | to links to quotes to lists to embedded images and galleries. 23 | The rich text content generated by the Trix editor is saved in its own 24 | RichText model that's associated with any existing Active Record model in the application. 25 | Any embedded images (or other attachments) are automatically stored using 26 | Active Storage and associated with the included RichText model. 27 | 28 | ## Trix compared to other rich text editors 29 | 30 | Most WYSIWYG editors are wrappers around HTML’s `contenteditable` and `execCommand` APIs, 31 | designed by Microsoft to support live editing of web pages in Internet Explorer 5.5, 32 | and [eventually reverse-engineered](https://blog.whatwg.org/the-road-to-html-5-contenteditable#history) 33 | and copied by other browsers. 34 | 35 | Because these APIs were never fully specified or documented, 36 | and because WYSIWYG HTML editors are enormous in scope, each 37 | browser's implementation has its own set of bugs and quirks, 38 | and JavaScript developers are left to resolve the inconsistencies. 39 | 40 | Trix sidesteps these inconsistencies by treating contenteditable 41 | as an I/O device: when input makes its way to the editor, Trix converts that input 42 | into an editing operation on its internal document model, then re-renders 43 | that document back into the editor. This gives Trix complete control over what 44 | happens after every keystroke, and avoids the need to use execCommand at all. 45 | 46 | ## Installation 47 | 48 | Run `rails action_text:install` to add the Yarn package and copy over the necessary migration. 49 | Also, you need to set up Active Storage for embedded images and other attachments. 50 | Please refer to the [Active Storage Overview](active_storage_overview.md) guide. 51 | 52 | ## Examples 53 | 54 | Adding a rich text field to an existing model: 55 | 56 | ```ruby 57 | # app/models/message.rb 58 | class Message < ApplicationRecord 59 | has_rich_text :content 60 | end 61 | ``` 62 | 63 | Then refer to this field in the form for the model: 64 | 65 | ```erb 66 | <%# app/views/messages/_form.html.erb %> 67 | <%= form_with(model: message) do |form| %> 68 |
69 | <%= form.label :content %> 70 | <%= form.rich_text_area :content %> 71 |
72 | <% end %> 73 | ``` 74 | 75 | And finally display the sanitized rich text on a page: 76 | 77 | ```erb 78 | <%= @message.content %> 79 | ``` 80 | 81 | To accept the rich text content, all you have to do is permit the referenced attribute: 82 | 83 | ```ruby 84 | class MessagesController < ApplicationController 85 | def create 86 | message = Message.create! params.require(:message).permit(:title, :content) 87 | redirect_to message 88 | end 89 | end 90 | ``` 91 | 92 | ## Custom styling 93 | 94 | By default, the Action Text editor and content is styled by the Trix defaults. 95 | If you want to change these defaults, you'll want to remove 96 | the `app/assets/stylesheets/actiontext.scss` linker and base your stylings on 97 | the [contents of that file](https://raw.githubusercontent.com/basecamp/trix/master/dist/trix.css). 98 | 99 | You can also style the HTML used for embedded images and other attachments (known as blobs). 100 | On installation, Action Text will copy over a partial to 101 | `app/views/active_storage/blobs/_blob.html.erb`, which you can specialize. 102 | -------------------------------------------------------------------------------- /docs/rails/active_record_multiple_databases.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: multiple-databases 3 | title: Multiple Databases with Active Record 4 | --- 5 | 6 | This guide covers using multiple databases with your Rails application. 7 | 8 | After reading this guide you will know: 9 | 10 | * How to setup your application for multiple databases. 11 | * How automatic connection switching works. 12 | * What features are supported and what's still a work in progress. 13 | 14 | -------------------------------------------------------------------------------- 15 | 16 | As an application grows in popularity and usage you'll need to scale the application 17 | to support your new users and their data. One way in which your application may need 18 | to scale is on the database level. Rails now has support for multiple databases 19 | so you don't have to store your data all in one place. 20 | 21 | At this time the following features are supported: 22 | 23 | * Multiple primary databases and a replica for each 24 | * Automatic connection switching for the model you're working with 25 | * Automatic swapping between the primary and replica depending on the HTTP verb 26 | and recent writes 27 | * Rails tasks for creating, dropping, migrating, and interacting with the multiple 28 | databases 29 | 30 | The following features are not (yet) supported: 31 | 32 | * Sharding 33 | * Joining across clusters 34 | * Load balancing replicas 35 | 36 | ## Setting up your application 37 | 38 | While Rails tries to do most of the work for you there are still some steps you'll 39 | need to do to get your application ready for multiple databases. 40 | 41 | Let's say we have an application with a single primary database and we need to add a 42 | new database for some new tables we're adding. The name of the new database will be 43 | "animals". 44 | 45 | The database.yml looks like this: 46 | 47 | ```yaml 48 | production: 49 | database: my_primary_database 50 | user: root 51 | adapter: mysql 52 | ``` 53 | 54 | Let's add a replica for the primary, a new writer called animals and a replica for that 55 | as well. To do this we need to change our database.yml from a 2-tier to a 3-tier config. 56 | 57 | ```yaml 58 | production: 59 | primary: 60 | database: my_primary_database 61 | user: root 62 | adapter: mysql 63 | primary_replica: 64 | database: my_primary_database 65 | user: root_readonly 66 | adapter: mysql 67 | replica: true 68 | animals: 69 | database: my_animals_database 70 | user: animals_root 71 | adapter: mysql 72 | migrations_paths: db/animals_migrate 73 | animals_replica: 74 | database: my_animals_database 75 | user: animals_readonly 76 | adapter: mysql 77 | replica: true 78 | ``` 79 | 80 | When using multiple databases there are a few important settings. 81 | 82 | First, the database name for the primary and replica should be the same because they contain 83 | the same data. Second, the username for the primary and replica should be different, and the 84 | replica user's permissions should be to read and not write. 85 | 86 | When using a replica database you need to add a `replica: true` entry to the replica in the 87 | `database.yml`. This is because Rails otherwise has no way of knowing which one is a replica 88 | and which one is the primary. 89 | 90 | Lastly, for new primary databases you need to set the `migrations_paths` to the directory 91 | where you will store migrations for that database. We'll look more at `migrations_paths` 92 | later on in this guide. 93 | 94 | Now that we have a new database, let's set up the model. In order to use the new database we 95 | need to create a new abstract class and connect to the animals databases. 96 | 97 | ```ruby 98 | class AnimalsBase < ApplicationRecord 99 | self.abstract_class = true 100 | 101 | connects_to database: { writing: :animals, reading: :animals_replica } 102 | end 103 | ``` 104 | Then we need to 105 | update `ApplicationRecord` to be aware of our new replica. 106 | 107 | ```ruby 108 | class ApplicationRecord < ActiveRecord::Base 109 | self.abstract_class = true 110 | 111 | connects_to database: { writing: :primary, reading: :primary_replica } 112 | end 113 | ``` 114 | 115 | By default Rails expects the database roles to be `writing` and `reading` for the primary 116 | and replica respectively. If you have a legacy system you may already have roles set up that 117 | you don't want to change. In that case you can set a new role name in your application config. 118 | 119 | ```ruby 120 | config.active_record.writing_role = :default 121 | config.active_record.reading_role = :readonly 122 | ``` 123 | 124 | Now that we have the database.yml and the new model set up it's time to create the databases. 125 | Rails 6.0 ships with all the rails tasks you need to use multiple databases in Rails. 126 | 127 | You can run `rails -T` to see all the commands you're able to run. You should see the following: 128 | 129 | ``` 130 | $ rails -T 131 | rails db:create # Creates the database from DATABASE_URL or config/database.yml for the ... 132 | rails db:create:animals # Create animals database for current environment 133 | rails db:create:primary # Create primary database for current environment 134 | rails db:drop # Drops the database from DATABASE_URL or config/database.yml for the cu... 135 | rails db:drop:animals # Drop animals database for current environment 136 | rails db:drop:primary # Drop primary database for current environment 137 | rails db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog) 138 | rails db:migrate:animals # Migrate animals database for current environment 139 | rails db:migrate:primary # Migrate primary database for current environment 140 | rails db:migrate:status # Display status of migrations 141 | rails db:migrate:status:animals # Display status of migrations for animals database 142 | rails db:migrate:status:primary # Display status of migrations for primary database 143 | ``` 144 | 145 | Running a command like `rails db:create` will create both the primary and animals databases. 146 | Note that there is no command for creating the users and you'll need to do that manually 147 | to support the readonly users for your replicas. If you want to create just the animals 148 | database you can run `rails db:create:animals`. 149 | 150 | ## Migrations 151 | 152 | Migrations for multiple databases should live in their own folders prefixed with the 153 | name of the database key in the configuration. 154 | 155 | You also need to set the `migrations_paths` in the database configurations to tell Rails 156 | where to find the migrations. 157 | 158 | For example the `animals` database would look in the `db/animals_migrate` directory and 159 | `primary` would look in `db/migrate`. Rails generators now take a `--database` option 160 | so that the file is generated in the correct directory. The command can be run like so: 161 | 162 | ``` 163 | $ rails g migration CreateDogs name:string --database animals 164 | ``` 165 | 166 | ## Activating automatic connection switching 167 | 168 | Finally, in order to use the read-only replica in your application you'll need to activate 169 | the middleware for automatic switching. 170 | 171 | Automatic switching allows the application to switch from the primary to replica or replica 172 | to primary based on the HTTP verb and whether there was a recent write. 173 | 174 | If the application is receiving a POST, PUT, DELETE, or PATCH request the application will 175 | automatically write to the primary. For the specified time after the write the application 176 | will read from the replica. For a GET or HEAD request the application will read from the 177 | replica unless there was a recent write. 178 | 179 | To activate the automatic connection switching middleware, add or uncomment the following 180 | lines in your application config. 181 | 182 | ```ruby 183 | config.active_record.database_selector = { delay: 2.seconds } 184 | config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 185 | config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 186 | ``` 187 | 188 | Rails guarantees "read your own write" and will send your GET or HEAD request to the 189 | primary if it's within the `delay` window. By default the delay is set to 2 seconds. You 190 | should change this based on your database infrastructure. Rails doesn't guarantee "read 191 | a recent write" for other users within the delay window and will send GET and HEAD requests 192 | to the replicas unless they wrote recently. 193 | 194 | The automatic connection switching in Rails is relatively primitive and deliberately doesn't 195 | do a whole lot. The goal was a system that demonstrated how to do automatic connection 196 | switching that was flexible enough to be customizable by app developers. 197 | 198 | The setup in Rails allows you to easily change how the switching is done and what 199 | parameters it's based on. Let's say you want to use a cookie instead of a session to 200 | decide when to swap connections. You can write your own class: 201 | 202 | ```ruby 203 | class MyCookieResolver 204 | # code for your cookie class 205 | end 206 | ``` 207 | 208 | And then pass it to the middleware: 209 | 210 | ```ruby 211 | config.active_record.database_selector = { delay: 2.seconds } 212 | config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 213 | config.active_record.database_resolver_context = MyCookieResolver 214 | ``` 215 | 216 | ## Using manual connection switching 217 | 218 | There are some cases where you may want your application to connect to a primary or a replica 219 | and the automatic connection switching isn't adequate. For example, you may know that for a 220 | particular request you always want to send the request to a replica, even when you are in a 221 | POST request path. 222 | 223 | To do this Rails provides a `connected_to` method that will switch to the connection you 224 | need. 225 | 226 | ```ruby 227 | ActiveRecord::Base.connected_to(role: :reading) do 228 | # all code in this block will be connected to the reading role 229 | end 230 | ``` 231 | 232 | The "role" in the `connected_to` call looks up the connections that are connected on that 233 | connection handler (or role). The `reading` connection handler will hold all the connections 234 | that were connected via `connects_to` with the role name of `reading`. 235 | 236 | There also may be a case where you have a database that you don't always want to connect to 237 | on application boot but may need for a slow query or analytics. After defining that database 238 | in the database.yml you can connect by passing a database argument to `connected_to` 239 | 240 | ```ruby 241 | ActiveRecord::Base.connected_to(database: { reading_slow: :animals_slow_replica }) do 242 | # do something while connected to the slow replica 243 | end 244 | ``` 245 | 246 | The `database` argument for `connected_to` will take a symbol or a config hash. 247 | 248 | Note that `connected_to` with a role will look up an existing connection and switch 249 | using the connection specification name. This means that if you pass an unknown role 250 | like `connected_to(role: :nonexistent)` you will get an error that says 251 | `ActiveRecord::ConnectionNotEstablished (No connection pool with 'AnimalsBase' found 252 | for the 'nonexistent' role.)` 253 | 254 | ## Caveats 255 | 256 | As noted at the top, Rails doesn't (yet) support sharding. We had to do a lot of work 257 | to support multiple databases for Rails 6.0. The lack of support for sharding isn't 258 | an oversight, but does require additional work that didn't make it in for 6.0. For now 259 | if you need sharding it may be advisable to continue using one of the many gems 260 | that supports this. 261 | 262 | Rails also doesn't support automatic load balancing of replicas. This is very 263 | dependent on your infrastructure. We may implement basic, primitive load balancing 264 | in the future, but for an application at scale this should be something your application 265 | handles outside of Rails. 266 | 267 | Lastly, you cannot join across databases. Rails 6.1 will support using `has_many` 268 | relationships and creating 2 queries instead of joining, but Rails 6.0 will require 269 | you to split the joins into 2 selects manually. 270 | -------------------------------------------------------------------------------- /docs/rails/development_dependencies_install.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: development-dependencies-install 3 | title: Development Dependencies Install 4 | --- 5 | 6 | This guide covers how to setup an environment for Ruby on Rails core development. 7 | 8 | After reading this guide, you will know: 9 | 10 | * How to set up your machine for Rails development 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | The Easy Way 15 | ------------ 16 | 17 | The easiest and recommended way to get a development environment ready to hack is to use the [Rails development box](https://github.com/rails/rails-dev-box). 18 | 19 | The Hard Way 20 | ------------ 21 | 22 | In case you can't use the Rails development box, see the steps below to manually 23 | build a development box for Ruby on Rails core development. 24 | 25 | ### Install Git 26 | 27 | Ruby on Rails uses Git for source code control. The [Git homepage](https://git-scm.com/) has installation instructions. There are a variety of resources on the net that will help you get familiar with Git: 28 | 29 | * [Try Git course](https://try.github.io/) is an interactive course that will teach you the basics. 30 | * The [official Documentation](https://git-scm.com/documentation) is pretty comprehensive and also contains some videos with the basics of Git. 31 | * [Everyday Git](https://schacon.github.io/git/everyday.html) will teach you just enough about Git to get by. 32 | * [GitHub](https://help.github.com/) offers links to a variety of Git resources. 33 | * [Pro Git](https://git-scm.com/book) is an entire book about Git with a Creative Commons license. 34 | 35 | ### Clone the Ruby on Rails Repository 36 | 37 | Navigate to the folder where you want the Ruby on Rails source code (it will create its own `rails` subdirectory) and run: 38 | 39 | ```bash 40 | $ git clone https://github.com/rails/rails.git 41 | $ cd rails 42 | ``` 43 | 44 | ### Install Additional Tools and Services 45 | 46 | Some Rails tests depend on additional tools that you need to install before running those specific tests. 47 | 48 | Here's the list of each gems' additional dependencies: 49 | 50 | * Action Cable depends on Redis 51 | * Active Record depends on SQLite3, MySQL and PostgreSQL 52 | * Active Storage depends on Yarn (additionally Yarn depends on 53 | [Node.js](https://nodejs.org/)), ImageMagick, FFmpeg, muPDF, and on macOS 54 | also XQuartz and Poppler. 55 | * Active Support depends on memcached and Redis 56 | * Railties depend on a JavaScript runtime environment, such as having 57 | [Node.js](https://nodejs.org/) installed. 58 | 59 | Install all the services you need to properly test the full gem you'll be 60 | making changes to. 61 | 62 | NOTE: Redis' documentation discourage installations with package managers as those are usually outdated. Installing from source and bringing the server up is straight forward and well documented on [Redis' documentation](https://redis.io/download#installation). 63 | 64 | NOTE: Active Record tests _must_ pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against single adapter. 65 | 66 | Below you can find instructions on how to install all of the additional 67 | tools for different OSes. 68 | 69 | #### macOS 70 | 71 | On macOS you can use [Homebrew](https://brew.sh/) to install all of the 72 | additional tools. 73 | 74 | To install all run: 75 | 76 | ```bash 77 | $ brew bundle 78 | ``` 79 | 80 | You'll also need to start each of the installed services. To list all 81 | available services run: 82 | 83 | ```bash 84 | $ brew services list 85 | ``` 86 | 87 | You can then start each of the services one by one like this: 88 | 89 | ```bash 90 | $ brew services start mysql 91 | ``` 92 | 93 | Replace `mysql` with the name of the service you want to start. 94 | 95 | #### Ubuntu 96 | 97 | To install all run: 98 | 99 | ```bash 100 | $ sudo apt-get update 101 | $ sudo apt-get install sqlite3 libsqlite3-dev 102 | mysql-server libmysqlclient-dev 103 | postgresql postgresql-client postgresql-contrib libpq-dev 104 | redis-server memcached imagemagick ffmpeg mupdf mupdf-tools 105 | 106 | # Install Yarn 107 | $ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - 108 | $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list 109 | $ sudo apt-get install yarn 110 | ``` 111 | 112 | #### Fedora or CentOS 113 | 114 | To install all run: 115 | 116 | ```bash 117 | $ sudo dnf install sqlite-devel sqlite-libs 118 | mysql-server mysql-devel 119 | postgresql-server postgresql-devel 120 | redis memcached imagemagick ffmpeg mupdf 121 | 122 | # Install Yarn 123 | # Use this command if you do not have Node.js installed 124 | $ curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - 125 | # If you have Node.js installed, use this command instead 126 | $ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo 127 | $ sudo dnf install yarn 128 | ``` 129 | 130 | #### Arch Linux 131 | 132 | To install all run: 133 | 134 | ```bash 135 | $ sudo pacman -S sqlite 136 | mariadb libmariadbclient mariadb-clients 137 | postgresql postgresql-libs 138 | redis memcached imagemagick ffmpeg mupdf mupdf-tools poppler 139 | yarn 140 | $ sudo systemctl start redis 141 | ``` 142 | 143 | NOTE: If you are running Arch Linux, MySQL isn't supported anymore so you will need to 144 | use MariaDB instead (see [this announcement](https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/)). 145 | 146 | #### FreeBSD 147 | 148 | To install all run: 149 | 150 | ```bash 151 | # pkg install sqlite3 152 | mysql80-client mysql80-server 153 | postgresql11-client postgresql11-server 154 | memcached imagemagick ffmpeg mupdf 155 | yarn 156 | # portmaster databases/redis 157 | ``` 158 | 159 | Or install everything through ports (these packages are located under the 160 | `databases` folder). 161 | 162 | NOTE: If you run into troubles during the installation of MySQL, please see 163 | [the MySQL documentation](https://dev.mysql.com/doc/refman/8.0/en/freebsd-installation.html). 164 | 165 | ### Database Configuration 166 | 167 | There are couple of additional steps required to configure database engines 168 | required for running Active Record tests. 169 | 170 | In order to be able to run the test suite against MySQL you need to create a user named `rails` with privileges on the test databases: 171 | 172 | ```bash 173 | $ mysql -uroot -p 174 | 175 | mysql> CREATE USER 'rails'@'localhost'; 176 | mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.* 177 | to 'rails'@'localhost'; 178 | mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.* 179 | to 'rails'@'localhost'; 180 | mysql> GRANT ALL PRIVILEGES ON inexistent_activerecord_unittest.* 181 | to 'rails'@'localhost'; 182 | ``` 183 | 184 | PostgreSQL's authentication works differently. To setup the development environment 185 | with your development account, on Linux or BSD, you just have to run: 186 | 187 | ```bash 188 | $ sudo -u postgres createuser --superuser $USER 189 | ``` 190 | 191 | and for macOS: 192 | 193 | ```bash 194 | $ createuser --superuser $USER 195 | ``` 196 | 197 | Then, you need to create the test databases for both MySQL and PostgreSQL with: 198 | 199 | ```bash 200 | $ cd activerecord 201 | $ bundle exec rake db:create 202 | ``` 203 | 204 | NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator". 205 | 206 | You can also create test databases for each database engine separately: 207 | 208 | ```bash 209 | $ cd activerecord 210 | $ bundle exec rake db:mysql:build 211 | $ bundle exec rake db:postgresql:build 212 | ``` 213 | 214 | and you can drop the databases using: 215 | 216 | ```bash 217 | $ cd activerecord 218 | $ bundle exec rake db:drop 219 | ``` 220 | 221 | NOTE: Using the Rake task to create the test databases ensures they have the correct character set and collation. 222 | 223 | If you're using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails. 224 | 225 | ### Install JavaScript dependencies 226 | 227 | If you installed Yarn, you will need to install the javascript dependencies: 228 | 229 | ```bash 230 | $ yarn install 231 | ``` 232 | 233 | ### Install Bundler gem 234 | 235 | Get a recent version of [Bundler](https://bundler.io/) 236 | 237 | ```bash 238 | $ gem install bundler 239 | $ gem update bundler 240 | ``` 241 | 242 | and run: 243 | 244 | ```bash 245 | $ bundle install 246 | ``` 247 | 248 | or: 249 | 250 | ```bash 251 | $ bundle install --without db 252 | ``` 253 | 254 | if you don't need to run Active Record tests. 255 | 256 | ### Contribute to Rails 257 | 258 | After you've setup everything, read how you can start [contributing](contributing_to_ruby_on_rails.html#running-an-application-against-your-local-branch). 259 | -------------------------------------------------------------------------------- /docs/rails/maintenance_policy.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: maintenance-policy 3 | title: Maintenance Policy for Ruby on Rails 4 | --- 5 | 6 | Support of the Rails framework is divided into four groups: New features, bug 7 | fixes, security issues, and severe security issues. They are handled as 8 | follows, all versions in `X.Y.Z` format. 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | Rails follows a shifted version of [semver](http://semver.org/): 13 | 14 | **Patch `Z`** 15 | 16 | Only bug fixes, no API changes, no new features. 17 | Except as necessary for security fixes. 18 | 19 | **Minor `Y`** 20 | 21 | New features, may contain API changes (Serve as major versions of Semver). 22 | Breaking changes are paired with deprecation notices in the previous minor 23 | or major release. 24 | 25 | **Major `X`** 26 | 27 | New features, will likely contain API changes. The difference between Rails' 28 | minor and major releases is the magnitude of breaking changes, and usually 29 | reserved for special occasions. 30 | 31 | New Features 32 | ------------ 33 | 34 | New features are only added to the master branch and will not be made available 35 | in point releases. 36 | 37 | Bug Fixes 38 | --------- 39 | 40 | Only the latest release series will receive bug fixes. When enough bugs are 41 | fixed and its deemed worthy to release a new gem, this is the branch it happens 42 | from. 43 | 44 | In special situations, where someone from the Core Team agrees to support more series, 45 | they are included in the list of supported series. 46 | 47 | **Currently included series:** `5.2.Z`. 48 | 49 | Security Issues 50 | --------------- 51 | 52 | The current release series and the next most recent one will receive patches 53 | and new versions in case of a security issue. 54 | 55 | These releases are created by taking the last released version, applying the 56 | security patches, and releasing. Those patches are then applied to the end of 57 | the x-y-stable branch. For example, a theoretical 1.2.3 security release would 58 | be built from 1.2.2, and then added to the end of 1-2-stable. This means that 59 | security releases are easy to upgrade to if you're running the latest version 60 | of Rails. 61 | 62 | **Currently included series:** `5.2.Z`, `5.1.Z`. 63 | 64 | Severe Security Issues 65 | ---------------------- 66 | 67 | For severe security issues all releases in the current major series, and also the 68 | last major release series will receive patches and new versions. The 69 | classification of the security issue is judged by the core team. 70 | 71 | **Currently included series:** `5.2.Z`, `5.1.Z`, `5.0.Z`, `4.2.Z`. 72 | 73 | Unsupported Release Series 74 | -------------------------- 75 | 76 | When a release series is no longer supported, it's your own responsibility to 77 | deal with bugs and security issues. We may provide backports of the fixes and 78 | publish them to git, however there will be no new versions released. If you are 79 | not comfortable maintaining your own versions, you should upgrade to a 80 | supported version. 81 | -------------------------------------------------------------------------------- /docs/rails/rails_application_templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: application-templates 3 | title: Rails Application Templates 4 | --- 5 | 6 | Application templates are simple Ruby files containing DSL for adding gems/initializers etc. to your freshly created Rails project or an existing Rails project. 7 | 8 | After reading this guide, you will know: 9 | 10 | * How to use templates to generate/customize Rails applications. 11 | * How to write your own reusable application templates using the Rails template API. 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | Usage 16 | ----- 17 | 18 | To apply a template, you need to provide the Rails generator with the location of the template you wish to apply using the `-m` option. This can either be a path to a file or a URL. 19 | 20 | ```bash 21 | $ rails new blog -m ~/template.rb 22 | $ rails new blog -m http://example.com/template.rb 23 | ``` 24 | 25 | You can use the `app:template` rails command to apply templates to an existing Rails application. The location of the template needs to be passed in via the LOCATION environment variable. Again, this can either be path to a file or a URL. 26 | 27 | ```bash 28 | $ rails app:template LOCATION=~/template.rb 29 | $ rails app:template LOCATION=http://example.com/template.rb 30 | ``` 31 | 32 | Template API 33 | ------------ 34 | 35 | The Rails templates API is easy to understand. Here's an example of a typical Rails template: 36 | 37 | ```ruby 38 | # template.rb 39 | generate(:scaffold, "person name:string") 40 | route "root to: 'people#index'" 41 | rails_command("db:migrate") 42 | 43 | after_bundle do 44 | git :init 45 | git add: "." 46 | git commit: %Q{ -m 'Initial commit' } 47 | end 48 | ``` 49 | 50 | The following sections outline the primary methods provided by the API: 51 | 52 | ### gem(*args) 53 | 54 | Adds a `gem` entry for the supplied gem to the generated application's `Gemfile`. 55 | 56 | For example, if your application depends on the gems `bj` and `nokogiri`: 57 | 58 | ```ruby 59 | gem "bj" 60 | gem "nokogiri" 61 | ``` 62 | 63 | Please note that this will NOT install the gems for you and you will have to run `bundle install` to do that. 64 | 65 | ```bash 66 | bundle install 67 | ``` 68 | 69 | ### gem_group(*names, &block) 70 | 71 | Wraps gem entries inside a group. 72 | 73 | For example, if you want to load `rspec-rails` only in the `development` and `test` groups: 74 | 75 | ```ruby 76 | gem_group :development, :test do 77 | gem "rspec-rails" 78 | end 79 | ``` 80 | 81 | ### add_source(source, options={}, &block) 82 | 83 | Adds the given source to the generated application's `Gemfile`. 84 | 85 | For example, if you need to source a gem from `"http://code.whytheluckystiff.net"`: 86 | 87 | ```ruby 88 | add_source "http://code.whytheluckystiff.net" 89 | ``` 90 | 91 | If block is given, gem entries in block are wrapped into the source group. 92 | 93 | ```ruby 94 | add_source "http://gems.github.com/" do 95 | gem "rspec-rails" 96 | end 97 | ``` 98 | 99 | ### environment/application(data=nil, options={}, &block) 100 | 101 | Adds a line inside the `Application` class for `config/application.rb`. 102 | 103 | If `options[:env]` is specified, the line is appended to the corresponding file in `config/environments`. 104 | 105 | ```ruby 106 | environment 'config.action_mailer.default_url_options = {host: "http://yourwebsite.example.com"}', env: 'production' 107 | ``` 108 | 109 | A block can be used in place of the `data` argument. 110 | 111 | ### vendor/lib/file/initializer(filename, data = nil, &block) 112 | 113 | Adds an initializer to the generated application's `config/initializers` directory. 114 | 115 | Let's say you like using `Object#not_nil?` and `Object#not_blank?`: 116 | 117 | ```ruby 118 | initializer 'bloatlol.rb', <<-CODE 119 | class Object 120 | def not_nil? 121 | !nil? 122 | end 123 | 124 | def not_blank? 125 | !blank? 126 | end 127 | end 128 | CODE 129 | ``` 130 | 131 | Similarly, `lib()` creates a file in the `lib/` directory and `vendor()` creates a file in the `vendor/` directory. 132 | 133 | There is even `file()`, which accepts a relative path from `Rails.root` and creates all the directories/files needed: 134 | 135 | ```ruby 136 | file 'app/components/foo.rb', <<-CODE 137 | class Foo 138 | end 139 | CODE 140 | ``` 141 | 142 | That'll create the `app/components` directory and put `foo.rb` in there. 143 | 144 | ### rakefile(filename, data = nil, &block) 145 | 146 | Creates a new rake file under `lib/tasks` with the supplied tasks: 147 | 148 | ```ruby 149 | rakefile("bootstrap.rake") do 150 | <<-TASK 151 | namespace :boot do 152 | task :strap do 153 | puts "i like boots!" 154 | end 155 | end 156 | TASK 157 | end 158 | ``` 159 | 160 | The above creates `lib/tasks/bootstrap.rake` with a `boot:strap` rake task. 161 | 162 | ### generate(what, *args) 163 | 164 | Runs the supplied rails generator with given arguments. 165 | 166 | ```ruby 167 | generate(:scaffold, "person", "name:string", "address:text", "age:number") 168 | ``` 169 | 170 | ### run(command) 171 | 172 | Executes an arbitrary command. Just like the backticks. Let's say you want to remove the `README.rdoc` file: 173 | 174 | ```ruby 175 | run "rm README.rdoc" 176 | ``` 177 | 178 | ### rails_command(command, options = {}) 179 | 180 | Runs the supplied command in the Rails application. Let's say you want to migrate the database: 181 | 182 | ```ruby 183 | rails_command "db:migrate" 184 | ``` 185 | 186 | You can also run commands with a different Rails environment: 187 | 188 | ```ruby 189 | rails_command "db:migrate", env: 'production' 190 | ``` 191 | 192 | You can also run commands as a super-user: 193 | 194 | ```ruby 195 | rails_command "log:clear", sudo: true 196 | ``` 197 | 198 | You can also run commands that should abort application generation if they fail: 199 | 200 | ```ruby 201 | rails_command "db:migrate", abort_on_failure: true 202 | ``` 203 | 204 | ### route(routing_code) 205 | 206 | Adds a routing entry to the `config/routes.rb` file. In the steps above, we generated a person scaffold and also removed `README.rdoc`. Now, to make `PeopleController#index` the default page for the application: 207 | 208 | ```ruby 209 | route "root to: 'person#index'" 210 | ``` 211 | 212 | ### inside(dir) 213 | 214 | Enables you to run a command from the given directory. For example, if you have a copy of edge rails that you wish to symlink from your new apps, you can do this: 215 | 216 | ```ruby 217 | inside('vendor') do 218 | run "ln -s ~/commit-rails/rails rails" 219 | end 220 | ``` 221 | 222 | ### ask(question) 223 | 224 | `ask()` gives you a chance to get some feedback from the user and use it in your templates. Let's say you want your user to name the new shiny library you're adding: 225 | 226 | ```ruby 227 | lib_name = ask("What do you want to call the shiny library ?") 228 | lib_name << ".rb" unless lib_name.index(".rb") 229 | 230 | lib lib_name, <<-CODE 231 | class Shiny 232 | end 233 | CODE 234 | ``` 235 | 236 | ### yes?(question) or no?(question) 237 | 238 | These methods let you ask questions from templates and decide the flow based on the user's answer. Let's say you want to Freeze Rails only if the user wants to: 239 | 240 | ```ruby 241 | rails_command("rails:freeze:gems") if yes?("Freeze rails gems?") 242 | # no?(question) acts just the opposite. 243 | ``` 244 | 245 | ### git(:command) 246 | 247 | Rails templates let you run any git command: 248 | 249 | ```ruby 250 | git :init 251 | git add: "." 252 | git commit: "-a -m 'Initial commit'" 253 | ``` 254 | 255 | ### after_bundle(&block) 256 | 257 | Registers a callback to be executed after the gems are bundled and binstubs 258 | are generated. Useful for all generated files to version control: 259 | 260 | ```ruby 261 | after_bundle do 262 | git :init 263 | git add: '.' 264 | git commit: "-a -m 'Initial commit'" 265 | end 266 | ``` 267 | 268 | The callbacks gets executed even if `--skip-bundle` and/or `--skip-spring` has 269 | been passed. 270 | 271 | Advanced Usage 272 | -------------- 273 | 274 | The application template is evaluated in the context of a 275 | `Rails::Generators::AppGenerator` instance. It uses the `apply` action 276 | provided by 277 | [Thor](https://github.com/erikhuda/thor/blob/master/lib/thor/actions.rb#L207). 278 | This means you can extend and change the instance to match your needs. 279 | 280 | For example by overwriting the `source_paths` method to contain the 281 | location of your template. Now methods like `copy_file` will accept 282 | relative paths to your template's location. 283 | 284 | ```ruby 285 | def source_paths 286 | [__dir__] 287 | end 288 | ``` 289 | -------------------------------------------------------------------------------- /docs/rails/rails_on_rack.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: rails-on-rack 3 | title: Rails on Rack 4 | --- 5 | 6 | This guide covers Rails integration with Rack and interfacing with other Rack components. 7 | 8 | After reading this guide, you will know: 9 | 10 | * How to use Rack Middlewares in your Rails applications. 11 | * Action Pack's internal Middleware stack. 12 | * How to define a custom Middleware stack. 13 | 14 | -------------------------------------------------------------------------------- 15 | 16 | WARNING: This guide assumes a working knowledge of Rack protocol and Rack concepts such as middlewares, URL maps, and `Rack::Builder`. 17 | 18 | Introduction to Rack 19 | -------------------- 20 | 21 | Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call. 22 | 23 | Explaining how Rack works is not really in the scope of this guide. In case you 24 | are not familiar with Rack's basics, you should check out the [Resources](#resources) 25 | section below. 26 | 27 | Rails on Rack 28 | ------------- 29 | 30 | ### Rails Application's Rack Object 31 | 32 | `Rails.application` is the primary Rack application object of a Rails 33 | application. Any Rack compliant web server should be using 34 | `Rails.application` object to serve a Rails application. 35 | 36 | ### `rails server` 37 | 38 | `rails server` does the basic job of creating a `Rack::Server` object and starting the web server. 39 | 40 | Here's how `rails server` creates an instance of `Rack::Server` 41 | 42 | ```ruby 43 | Rails::Server.new.tap do |server| 44 | require APP_PATH 45 | Dir.chdir(Rails.application.root) 46 | server.start 47 | end 48 | ``` 49 | 50 | The `Rails::Server` inherits from `Rack::Server` and calls the `Rack::Server#start` method this way: 51 | 52 | ```ruby 53 | class Server < ::Rack::Server 54 | def start 55 | ... 56 | super 57 | end 58 | end 59 | ``` 60 | 61 | ### `rackup` 62 | 63 | To use `rackup` instead of Rails' `rails server`, you can put the following inside `config.ru` of your Rails application's root directory: 64 | 65 | ```ruby 66 | # Rails.root/config.ru 67 | require_relative 'config/environment' 68 | run Rails.application 69 | ``` 70 | 71 | And start the server: 72 | 73 | ```bash 74 | $ rackup config.ru 75 | ``` 76 | 77 | To find out more about different `rackup` options, you can run: 78 | 79 | ```bash 80 | $ rackup --help 81 | ``` 82 | 83 | ### Development and auto-reloading 84 | 85 | Middlewares are loaded once and are not monitored for changes. You will have to restart the server for changes to be reflected in the running application. 86 | 87 | Action Dispatcher Middleware Stack 88 | ---------------------------------- 89 | 90 | Many of Action Dispatcher's internal components are implemented as Rack middlewares. `Rails::Application` uses `ActionDispatch::MiddlewareStack` to combine various internal and external middlewares to form a complete Rails Rack application. 91 | 92 | NOTE: `ActionDispatch::MiddlewareStack` is Rails' equivalent of `Rack::Builder`, 93 | but is built for better flexibility and more features to meet Rails' requirements. 94 | 95 | ### Inspecting Middleware Stack 96 | 97 | Rails has a handy command for inspecting the middleware stack in use: 98 | 99 | ```bash 100 | $ rails middleware 101 | ``` 102 | 103 | For a freshly generated Rails application, this might produce something like: 104 | 105 | ```ruby 106 | use Rack::Sendfile 107 | use ActionDispatch::Static 108 | use ActionDispatch::Executor 109 | use ActiveSupport::Cache::Strategy::LocalCache::Middleware 110 | use Rack::Runtime 111 | use Rack::MethodOverride 112 | use ActionDispatch::RequestId 113 | use ActionDispatch::RemoteIp 114 | use Sprockets::Rails::QuietAssets 115 | use Rails::Rack::Logger 116 | use ActionDispatch::ShowExceptions 117 | use WebConsole::Middleware 118 | use ActionDispatch::DebugExceptions 119 | use ActionDispatch::Reloader 120 | use ActionDispatch::Callbacks 121 | use ActiveRecord::Migration::CheckPending 122 | use ActionDispatch::Cookies 123 | use ActionDispatch::Session::CookieStore 124 | use ActionDispatch::Flash 125 | use ActionDispatch::ContentSecurityPolicy::Middleware 126 | use Rack::Head 127 | use Rack::ConditionalGet 128 | use Rack::ETag 129 | use Rack::TempfileReaper 130 | run MyApp::Application.routes 131 | ``` 132 | 133 | The default middlewares shown here (and some others) are each summarized in the [Internal Middlewares](#internal-middleware-stack) section, below. 134 | 135 | ### Configuring Middleware Stack 136 | 137 | Rails provides a simple configuration interface `config.middleware` for adding, removing, and modifying the middlewares in the middleware stack via `application.rb` or the environment specific configuration file `environments/.rb`. 138 | 139 | #### Adding a Middleware 140 | 141 | You can add a new middleware to the middleware stack using any of the following methods: 142 | 143 | * `config.middleware.use(new_middleware, args)` - Adds the new middleware at the bottom of the middleware stack. 144 | 145 | * `config.middleware.insert_before(existing_middleware, new_middleware, args)` - Adds the new middleware before the specified existing middleware in the middleware stack. 146 | 147 | * `config.middleware.insert_after(existing_middleware, new_middleware, args)` - Adds the new middleware after the specified existing middleware in the middleware stack. 148 | 149 | ```ruby 150 | # config/application.rb 151 | 152 | # Push Rack::BounceFavicon at the bottom 153 | config.middleware.use Rack::BounceFavicon 154 | 155 | # Add Lifo::Cache after ActionDispatch::Executor. 156 | # Pass { page_cache: false } argument to Lifo::Cache. 157 | config.middleware.insert_after ActionDispatch::Executor, Lifo::Cache, page_cache: false 158 | ``` 159 | 160 | #### Swapping a Middleware 161 | 162 | You can swap an existing middleware in the middleware stack using `config.middleware.swap`. 163 | 164 | ```ruby 165 | # config/application.rb 166 | 167 | # Replace ActionDispatch::ShowExceptions with Lifo::ShowExceptions 168 | config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions 169 | ``` 170 | 171 | #### Deleting a Middleware 172 | 173 | Add the following lines to your application configuration: 174 | 175 | ```ruby 176 | # config/application.rb 177 | config.middleware.delete Rack::Runtime 178 | ``` 179 | 180 | And now if you inspect the middleware stack, you'll find that `Rack::Runtime` is 181 | not a part of it. 182 | 183 | ```bash 184 | $ rails middleware 185 | (in /Users/lifo/Rails/blog) 186 | use ActionDispatch::Static 187 | use # 188 | ... 189 | run Rails.application.routes 190 | ``` 191 | 192 | If you want to remove session related middleware, do the following: 193 | 194 | ```ruby 195 | # config/application.rb 196 | config.middleware.delete ActionDispatch::Cookies 197 | config.middleware.delete ActionDispatch::Session::CookieStore 198 | config.middleware.delete ActionDispatch::Flash 199 | ``` 200 | 201 | And to remove browser related middleware, 202 | 203 | ```ruby 204 | # config/application.rb 205 | config.middleware.delete Rack::MethodOverride 206 | ``` 207 | 208 | ### Internal Middleware Stack 209 | 210 | Much of Action Controller's functionality is implemented as Middlewares. The following list explains the purpose of each of them: 211 | 212 | **`Rack::Sendfile`** 213 | 214 | * Sets server specific X-Sendfile header. Configure this via `config.action_dispatch.x_sendfile_header` option. 215 | 216 | **`ActionDispatch::Static`** 217 | 218 | * Used to serve static files from the public directory. Disabled if `config.public_file_server.enabled` is `false`. 219 | 220 | **`Rack::Lock`** 221 | 222 | * Sets `env["rack.multithread"]` flag to `false` and wraps the application within a Mutex. 223 | 224 | **`ActionDispatch::Executor`** 225 | 226 | * Used for thread safe code reloading during development. 227 | 228 | **`ActiveSupport::Cache::Strategy::LocalCache::Middleware`** 229 | 230 | * Used for memory caching. This cache is not thread safe. 231 | 232 | **`Rack::Runtime`** 233 | 234 | * Sets an X-Runtime header, containing the time (in seconds) taken to execute the request. 235 | 236 | **`Rack::MethodOverride`** 237 | 238 | * Allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PUT and DELETE HTTP method types. 239 | 240 | **`ActionDispatch::RequestId`** 241 | 242 | * Makes a unique `X-Request-Id` header available to the response and enables the `ActionDispatch::Request#request_id` method. 243 | 244 | **`ActionDispatch::RemoteIp`** 245 | 246 | * Checks for IP spoofing attacks. 247 | 248 | **`Sprockets::Rails::QuietAssets`** 249 | 250 | * Suppresses logger output for asset requests. 251 | 252 | **`Rails::Rack::Logger`** 253 | 254 | * Notifies the logs that the request has begun. After the request is complete, flushes all the logs. 255 | 256 | **`ActionDispatch::ShowExceptions`** 257 | 258 | * Rescues any exception returned by the application and calls an exceptions app that will wrap it in a format for the end user. 259 | 260 | **`ActionDispatch::DebugExceptions`** 261 | 262 | * Responsible for logging exceptions and showing a debugging page in case the request is local. 263 | 264 | **`ActionDispatch::Reloader`** 265 | 266 | * Provides prepare and cleanup callbacks, intended to assist with code reloading during development. 267 | 268 | **`ActionDispatch::Callbacks`** 269 | 270 | * Provides callbacks to be executed before and after dispatching the request. 271 | 272 | **`ActiveRecord::Migration::CheckPending`** 273 | 274 | * Checks pending migrations and raises `ActiveRecord::PendingMigrationError` if any migrations are pending. 275 | 276 | **`ActionDispatch::Cookies`** 277 | 278 | * Sets cookies for the request. 279 | 280 | **`ActionDispatch::Session::CookieStore`** 281 | 282 | * Responsible for storing the session in cookies. 283 | 284 | **`ActionDispatch::Flash`** 285 | 286 | * Sets up the flash keys. Only available if `config.action_controller.session_store` is set to a value. 287 | 288 | **`ActionDispatch::ContentSecurityPolicy::Middleware`** 289 | 290 | * Provides a DSL to configure a Content-Security-Policy header. 291 | 292 | **`Rack::Head`** 293 | 294 | * Converts HEAD requests to `GET` requests and serves them as so. 295 | 296 | **`Rack::ConditionalGet`** 297 | 298 | * Adds support for "Conditional `GET`" so that server responds with nothing if the page wasn't changed. 299 | 300 | **`Rack::ETag`** 301 | 302 | * Adds ETag header on all String bodies. ETags are used to validate cache. 303 | 304 | **`Rack::TempfileReaper`** 305 | 306 | * Cleans up tempfiles used to buffer multipart requests. 307 | 308 | TIP: It's possible to use any of the above middlewares in your custom Rack stack. 309 | 310 | Resources 311 | --------- 312 | 313 | ### Learning Rack 314 | 315 | * [Official Rack Website](https://rack.github.io) 316 | * [Introducing Rack](http://chneukirchen.org/blog/archive/2007/02/introducing-rack.html) 317 | 318 | ### Understanding Middlewares 319 | 320 | * [Railscast on Rack Middlewares](http://railscasts.com/episodes/151-rack-middleware) 321 | -------------------------------------------------------------------------------- /docs/rails/ruby_on_rails_guides_guidelines.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: guides-guidelines 3 | title: Ruby on Rails Guides Guidelines 4 | --- 5 | 6 | This guide documents guidelines for writing Ruby on Rails Guides. This guide follows itself in a graceful loop, serving itself as an example. 7 | 8 | After reading this guide, you will know: 9 | 10 | * About the conventions to be used in Rails documentation. 11 | * How to generate guides locally. 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | Markdown 16 | ------- 17 | 18 | Guides are written in [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown). There is comprehensive [documentation for Markdown](http://daringfireball.net/projects/markdown/syntax), as well as a [cheatsheet](http://daringfireball.net/projects/markdown/basics). 19 | 20 | Prologue 21 | -------- 22 | 23 | Each guide should start with motivational text at the top (that's the little introduction in the blue area). The prologue should tell the reader what the guide is about, and what they will learn. As an example, see the [Routing Guide](routing.md). 24 | 25 | Headings 26 | ------ 27 | 28 | The title of every guide uses an `h1` heading; guide sections use `h2` headings; subsections use `h3` headings; etc. Note that the generated HTML output will use heading tags starting with `

`. 29 | 30 | ``` 31 | Guide Title 32 | =========== 33 | 34 | Section 35 | ------- 36 | 37 | ### Sub Section 38 | ``` 39 | 40 | When writing headings, capitalize all words except for prepositions, conjunctions, internal articles, and forms of the verb "to be": 41 | 42 | ``` 43 | #### Middleware Stack is an Array 44 | #### When are Objects Saved? 45 | ``` 46 | 47 | Use the same inline formatting as regular text: 48 | 49 | ``` 50 | ##### The `:content_type` Option 51 | ``` 52 | 53 | Linking to the API 54 | ------------------ 55 | 56 | Links to the API (`api.rubyonrails.org`) are processed by the guides generator in the following manner: 57 | 58 | Links that include a release tag are left untouched. For example 59 | 60 | ``` 61 | https://api.rubyonrails.org/v5.0.1/classes/ActiveRecord/Attributes/ClassMethods.html 62 | ``` 63 | 64 | is not modified. 65 | 66 | Please use these in release notes, since they should point to the corresponding version no matter the target being generated. 67 | 68 | If the link does not include a release tag and edge guides are being generated, the domain is replaced by `edgeapi.rubyonrails.org`. For example, 69 | 70 | ``` 71 | https://api.rubyonrails.org/classes/ActionDispatch/Response.html 72 | ``` 73 | 74 | becomes 75 | 76 | ``` 77 | https://edgeapi.rubyonrails.org/classes/ActionDispatch/Response.html 78 | ``` 79 | 80 | If the link does not include a release tag and release guides are being generated, the Rails version is injected. For example, if we are generating the guides for v5.1.0 the link 81 | 82 | ``` 83 | https://api.rubyonrails.org/classes/ActionDispatch/Response.html 84 | ``` 85 | 86 | becomes 87 | 88 | ``` 89 | https://api.rubyonrails.org/v5.1.0/classes/ActionDispatch/Response.html 90 | ``` 91 | 92 | Please don't link to `edgeapi.rubyonrails.org` manually. 93 | 94 | 95 | API Documentation Guidelines 96 | ---------------------------- 97 | 98 | The guides and the API should be coherent and consistent where appropriate. In particular, these sections of the [API Documentation Guidelines](api_documentation_guidelines.md) also apply to the guides: 99 | 100 | * [Wording](api_documentation_guidelines.md#wording) 101 | * [English](api_documentation_guidelines.md#english) 102 | * [Example Code](api_documentation_guidelines.md#example-code) 103 | * [Filenames](api_documentation_guidelines.md#file-names) 104 | * [Fonts](api_documentation_guidelines.md#fonts) 105 | 106 | HTML Guides 107 | ----------- 108 | 109 | Before generating the guides, make sure that you have the latest version of 110 | Bundler installed on your system. You can find the latest Bundler version 111 | [here](https://rubygems.org/gems/bundler). As of this writing, it's v1.17.1. 112 | 113 | To install the latest version of Bundler, run `gem install bundler`. 114 | 115 | ### Generation 116 | 117 | To generate all the guides, just `cd` into the `guides` directory, run `bundle install`, and execute: 118 | 119 | ``` 120 | bundle exec rake guides:generate 121 | ``` 122 | 123 | or 124 | 125 | ``` 126 | bundle exec rake guides:generate:html 127 | ``` 128 | 129 | Resulting HTML files can be found in the `./output` directory. 130 | 131 | To process `my_guide.md` and nothing else use the `ONLY` environment variable: 132 | 133 | ``` 134 | touch my_guide.md 135 | bundle exec rake guides:generate ONLY=my_guide 136 | ``` 137 | 138 | By default, guides that have not been modified are not processed, so `ONLY` is rarely needed in practice. 139 | 140 | To force processing all the guides, pass `ALL=1`. 141 | 142 | If you want to generate guides in a language other than English, you can keep them in a separate directory under `source` (eg. `source/es`) and use the `GUIDES_LANGUAGE` environment variable: 143 | 144 | ``` 145 | bundle exec rake guides:generate GUIDES_LANGUAGE=es 146 | ``` 147 | 148 | If you want to see all the environment variables you can use to configure the generation script just run: 149 | 150 | ``` 151 | rake 152 | ``` 153 | 154 | ### Validation 155 | 156 | Please validate the generated HTML with: 157 | 158 | ``` 159 | bundle exec rake guides:validate 160 | ``` 161 | 162 | Particularly, titles get an ID generated from their content and this often leads to duplicates. Please set `WARNINGS=1` when generating guides to detect them. The warning messages suggest a solution. 163 | 164 | Kindle Guides 165 | ------------- 166 | 167 | ### Generation 168 | 169 | To generate guides for the Kindle, use the following rake task: 170 | 171 | ``` 172 | bundle exec rake guides:generate:kindle 173 | ``` 174 | -------------------------------------------------------------------------------- /docs/rails/threading_and_code_execution.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: threading 3 | title: Threading and Code Execution in Rails 4 | --- 5 | 6 | After reading this guide, you will know: 7 | 8 | * What code Rails will automatically execute concurrently 9 | * How to integrate manual concurrency with Rails internals 10 | * How to wrap all application code 11 | * How to affect application reloading 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | Automatic Concurrency 16 | --------------------- 17 | 18 | Rails automatically allows various operations to be performed at the same time. 19 | 20 | When using a threaded web server, such as the default Puma, multiple HTTP 21 | requests will be served simultaneously, with each request provided its own 22 | controller instance. 23 | 24 | Threaded Active Job adapters, including the built-in Async, will likewise 25 | execute several jobs at the same time. Action Cable channels are managed this 26 | way too. 27 | 28 | These mechanisms all involve multiple threads, each managing work for a unique 29 | instance of some object (controller, job, channel), while sharing the global 30 | process space (such as classes and their configurations, and global variables). 31 | As long as your code doesn't modify any of those shared things, it can mostly 32 | ignore that other threads exist. 33 | 34 | The rest of this guide describes the mechanisms Rails uses to make it "mostly 35 | ignorable", and how extensions and applications with special needs can use them. 36 | 37 | Executor 38 | -------- 39 | 40 | The Rails Executor separates application code from framework code: any time the 41 | framework invokes code you've written in your application, it will be wrapped by 42 | the Executor. 43 | 44 | The Executor consists of two callbacks: `to_run` and `to_complete`. The Run 45 | callback is called before the application code, and the Complete callback is 46 | called after. 47 | 48 | ### Default callbacks 49 | 50 | In a default Rails application, the Executor callbacks are used to: 51 | 52 | * track which threads are in safe positions for autoloading and reloading 53 | * enable and disable the Active Record query cache 54 | * return acquired Active Record connections to the pool 55 | * constrain internal cache lifetimes 56 | 57 | Prior to Rails 5.0, some of these were handled by separate Rack middleware 58 | classes (such as `ActiveRecord::ConnectionAdapters::ConnectionManagement`), or 59 | directly wrapping code with methods like 60 | `ActiveRecord::Base.connection_pool.with_connection`. The Executor replaces 61 | these with a single more abstract interface. 62 | 63 | ### Wrapping application code 64 | 65 | If you're writing a library or component that will invoke application code, you 66 | should wrap it with a call to the executor: 67 | 68 | ```ruby 69 | Rails.application.executor.wrap do 70 | # call application code here 71 | end 72 | ``` 73 | 74 | TIP: If you repeatedly invoke application code from a long-running process, you 75 | may want to wrap using the Reloader instead. 76 | 77 | Each thread should be wrapped before it runs application code, so if your 78 | application manually delegates work to other threads, such as via `Thread.new` 79 | or Concurrent Ruby features that use thread pools, you should immediately wrap 80 | the block: 81 | 82 | ```ruby 83 | Thread.new do 84 | Rails.application.executor.wrap do 85 | # your code here 86 | end 87 | end 88 | ``` 89 | 90 | NOTE: Concurrent Ruby uses a `ThreadPoolExecutor`, which it sometimes configures 91 | with an `executor` option. Despite the name, it is unrelated. 92 | 93 | The Executor is safely re-entrant; if it is already active on the current 94 | thread, `wrap` is a no-op. 95 | 96 | If it's impractical to wrap the application code in a block (for 97 | example, the Rack API makes this problematic), you can also use the `run!` / 98 | `complete!` pair: 99 | 100 | ```ruby 101 | Thread.new do 102 | execution_context = Rails.application.executor.run! 103 | # your code here 104 | ensure 105 | execution_context.complete! if execution_context 106 | end 107 | ``` 108 | 109 | ### Concurrency 110 | 111 | The Executor will put the current thread into `running` mode in the Load 112 | Interlock. This operation will block temporarily if another thread is currently 113 | either autoloading a constant or unloading/reloading the application. 114 | 115 | Reloader 116 | -------- 117 | 118 | Like the Executor, the Reloader also wraps application code. If the Executor is 119 | not already active on the current thread, the Reloader will invoke it for you, 120 | so you only need to call one. This also guarantees that everything the Reloader 121 | does, including all its callback invocations, occurs wrapped inside the 122 | Executor. 123 | 124 | ```ruby 125 | Rails.application.reloader.wrap do 126 | # call application code here 127 | end 128 | ``` 129 | 130 | The Reloader is only suitable where a long-running framework-level process 131 | repeatedly calls into application code, such as for a web server or job queue. 132 | Rails automatically wraps web requests and Active Job workers, so you'll rarely 133 | need to invoke the Reloader for yourself. Always consider whether the Executor 134 | is a better fit for your use case. 135 | 136 | ### Callbacks 137 | 138 | Before entering the wrapped block, the Reloader will check whether the running 139 | application needs to be reloaded -- for example, because a model's source file has 140 | been modified. If it determines a reload is required, it will wait until it's 141 | safe, and then do so, before continuing. When the application is configured to 142 | always reload regardless of whether any changes are detected, the reload is 143 | instead performed at the end of the block. 144 | 145 | The Reloader also provides `to_run` and `to_complete` callbacks; they are 146 | invoked at the same points as those of the Executor, but only when the current 147 | execution has initiated an application reload. When no reload is deemed 148 | necessary, the Reloader will invoke the wrapped block with no other callbacks. 149 | 150 | ### Class Unload 151 | 152 | The most significant part of the reloading process is the Class Unload, where 153 | all autoloaded classes are removed, ready to be loaded again. This will occur 154 | immediately before either the Run or Complete callback, depending on the 155 | `reload_classes_only_on_change` setting. 156 | 157 | Often, additional reloading actions need to be performed either just before or 158 | just after the Class Unload, so the Reloader also provides `before_class_unload` 159 | and `after_class_unload` callbacks. 160 | 161 | ### Concurrency 162 | 163 | Only long-running "top level" processes should invoke the Reloader, because if 164 | it determines a reload is needed, it will block until all other threads have 165 | completed any Executor invocations. 166 | 167 | If this were to occur in a "child" thread, with a waiting parent inside the 168 | Executor, it would cause an unavoidable deadlock: the reload must occur before 169 | the child thread is executed, but it cannot be safely performed while the parent 170 | thread is mid-execution. Child threads should use the Executor instead. 171 | 172 | Framework Behavior 173 | ------------------ 174 | 175 | The Rails framework components use these tools to manage their own concurrency 176 | needs too. 177 | 178 | `ActionDispatch::Executor` and `ActionDispatch::Reloader` are Rack middlewares 179 | that wraps the request with a supplied Executor or Reloader, respectively. They 180 | are automatically included in the default application stack. The Reloader will 181 | ensure any arriving HTTP request is served with a freshly-loaded copy of the 182 | application if any code changes have occurred. 183 | 184 | Active Job also wraps its job executions with the Reloader, loading the latest 185 | code to execute each job as it comes off the queue. 186 | 187 | Action Cable uses the Executor instead: because a Cable connection is linked to 188 | a specific instance of a class, it's not possible to reload for every arriving 189 | websocket message. Only the message handler is wrapped, though; a long-running 190 | Cable connection does not prevent a reload that's triggered by a new incoming 191 | request or job. Instead, Action Cable uses the Reloader's `before_class_unload` 192 | callback to disconnect all its connections. When the client automatically 193 | reconnects, it will be speaking to the new version of the code. 194 | 195 | The above are the entry points to the framework, so they are responsible for 196 | ensuring their respective threads are protected, and deciding whether a reload 197 | is necessary. Other components only need to use the Executor when they spawn 198 | additional threads. 199 | 200 | ### Configuration 201 | 202 | The Reloader only checks for file changes when `cache_classes` is false and 203 | `reload_classes_only_on_change` is true (which is the default in the 204 | `development` environment). 205 | 206 | When `cache_classes` is true (in `production`, by default), the Reloader is only 207 | a pass-through to the Executor. 208 | 209 | The Executor always has important work to do, like database connection 210 | management. When `cache_classes` and `eager_load` are both true (`production`), 211 | no autoloading or class reloading will occur, so it does not need the Load 212 | Interlock. If either of those are false (`development`), then the Executor will 213 | use the Load Interlock to ensure constants are only loaded when it is safe. 214 | 215 | Load Interlock 216 | -------------- 217 | 218 | The Load Interlock allows autoloading and reloading to be enabled in a 219 | multi-threaded runtime environment. 220 | 221 | When one thread is performing an autoload by evaluating the class definition 222 | from the appropriate file, it is important no other thread encounters a 223 | reference to the partially-defined constant. 224 | 225 | Similarly, it is only safe to perform an unload/reload when no application code 226 | is in mid-execution: after the reload, the `User` constant, for example, may 227 | point to a different class. Without this rule, a poorly-timed reload would mean 228 | `User.new.class == User`, or even `User == User`, could be false. 229 | 230 | Both of these constraints are addressed by the Load Interlock. It keeps track of 231 | which threads are currently running application code, loading a class, or 232 | unloading autoloaded constants. 233 | 234 | Only one thread may load or unload at a time, and to do either, it must wait 235 | until no other threads are running application code. If a thread is waiting to 236 | perform a load, it doesn't prevent other threads from loading (in fact, they'll 237 | cooperate, and each perform their queued load in turn, before all resuming 238 | running together). 239 | 240 | ### `permit_concurrent_loads` 241 | 242 | The Executor automatically acquires a `running` lock for the duration of its 243 | block, and autoload knows when to upgrade to a `load` lock, and switch back to 244 | `running` again afterwards. 245 | 246 | Other blocking operations performed inside the Executor block (which includes 247 | all application code), however, can needlessly retain the `running` lock. If 248 | another thread encounters a constant it must autoload, this can cause a 249 | deadlock. 250 | 251 | For example, assuming `User` is not yet loaded, the following will deadlock: 252 | 253 | ```ruby 254 | Rails.application.executor.wrap do 255 | th = Thread.new do 256 | Rails.application.executor.wrap do 257 | User # inner thread waits here; it cannot load 258 | # User while another thread is running 259 | end 260 | end 261 | 262 | th.join # outer thread waits here, holding 'running' lock 263 | end 264 | ``` 265 | 266 | To prevent this deadlock, the outer thread can `permit_concurrent_loads`. By 267 | calling this method, the thread guarantees it will not dereference any 268 | possibly-autoloaded constant inside the supplied block. The safest way to meet 269 | that promise is to put it as close as possible to the blocking call: 270 | 271 | ```ruby 272 | Rails.application.executor.wrap do 273 | th = Thread.new do 274 | Rails.application.executor.wrap do 275 | User # inner thread can acquire the 'load' lock, 276 | # load User, and continue 277 | end 278 | end 279 | 280 | ActiveSupport::Dependencies.interlock.permit_concurrent_loads do 281 | th.join # outer thread waits here, but has no lock 282 | end 283 | end 284 | ``` 285 | 286 | Another example, using Concurrent Ruby: 287 | 288 | ```ruby 289 | Rails.application.executor.wrap do 290 | futures = 3.times.collect do |i| 291 | Concurrent::Future.execute do 292 | Rails.application.executor.wrap do 293 | # do work here 294 | end 295 | end 296 | end 297 | 298 | values = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do 299 | futures.collect(&:value) 300 | end 301 | end 302 | ``` 303 | 304 | 305 | ### ActionDispatch::DebugLocks 306 | 307 | If your application is deadlocking and you think the Load Interlock may be 308 | involved, you can temporarily add the ActionDispatch::DebugLocks middleware to 309 | `config/application.rb`: 310 | 311 | ```ruby 312 | config.middleware.insert_before Rack::Sendfile, 313 | ActionDispatch::DebugLocks 314 | ``` 315 | 316 | If you then restart the application and re-trigger the deadlock condition, 317 | `/rails/locks` will show a summary of all threads currently known to the 318 | interlock, which lock level they are holding or awaiting, and their current 319 | backtrace. 320 | 321 | Generally a deadlock will be caused by the interlock conflicting with some other 322 | external lock or blocking I/O call. Once you find it, you can wrap it with 323 | `permit_concurrent_loads`. 324 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rails-setup", 3 | "version": "0.0.1", 4 | "description": "this is a Project to collect in one place and in a friendly way the documentation for rails and commonly used related libraries", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "all-contributors-cli": "^6.7.0" 12 | }, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/HenryTabima/rails-setup.git" 19 | }, 20 | "keywords": [ 21 | "ruby-on-rails", 22 | "documentation" 23 | ], 24 | "author": "Henry Tabima Giraldo", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/HenryTabima/rails-setup/issues" 28 | }, 29 | "homepage": "https://github.com/HenryTabima/rails-setup#readme" 30 | } 31 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | This website was created with [Docusaurus](https://docusaurus.io/). 2 | 3 | # What's In This Document 4 | 5 | * [Get Started in 5 Minutes](#get-started-in-5-minutes) 6 | * [Directory Structure](#directory-structure) 7 | * [Editing Content](#editing-content) 8 | * [Adding Content](#adding-content) 9 | * [Full Documentation](#full-documentation) 10 | 11 | # Get Started in 5 Minutes 12 | 13 | 1. Make sure all the dependencies for the website are installed: 14 | 15 | ```sh 16 | # Install dependencies 17 | $ yarn 18 | ``` 19 | 2. Run your dev server: 20 | 21 | ```sh 22 | # Start the site 23 | $ yarn start 24 | ``` 25 | 26 | ## Directory Structure 27 | 28 | Your project file structure should look something like this 29 | 30 | ``` 31 | my-docusaurus/ 32 | docs/ 33 | doc-1.md 34 | doc-2.md 35 | doc-3.md 36 | website/ 37 | blog/ 38 | 2016-3-11-oldest-post.md 39 | 2017-10-24-newest-post.md 40 | core/ 41 | node_modules/ 42 | pages/ 43 | static/ 44 | css/ 45 | img/ 46 | package.json 47 | sidebar.json 48 | siteConfig.js 49 | ``` 50 | 51 | # Editing Content 52 | 53 | ## Editing an existing docs page 54 | 55 | Edit docs by navigating to `docs/` and editing the corresponding document: 56 | 57 | `docs/doc-to-be-edited.md` 58 | 59 | ```markdown 60 | --- 61 | id: page-needs-edit 62 | title: This Doc Needs To Be Edited 63 | --- 64 | 65 | Edit me... 66 | ``` 67 | 68 | For more information about docs, click [here](https://docusaurus.io/docs/en/navigation) 69 | 70 | ## Editing an existing blog post 71 | 72 | Edit blog posts by navigating to `website/blog` and editing the corresponding post: 73 | 74 | `website/blog/post-to-be-edited.md` 75 | ```markdown 76 | --- 77 | id: post-needs-edit 78 | title: This Blog Post Needs To Be Edited 79 | --- 80 | 81 | Edit me... 82 | ``` 83 | 84 | For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) 85 | 86 | # Adding Content 87 | 88 | ## Adding a new docs page to an existing sidebar 89 | 90 | 1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`: 91 | 92 | ```md 93 | --- 94 | id: newly-created-doc 95 | title: This Doc Needs To Be Edited 96 | --- 97 | 98 | My new content here.. 99 | ``` 100 | 101 | 1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: 102 | 103 | ```javascript 104 | // Add newly-created-doc to the Getting Started category of docs 105 | { 106 | "docs": { 107 | "Getting Started": [ 108 | "quick-start", 109 | "newly-created-doc" // new doc here 110 | ], 111 | ... 112 | }, 113 | ... 114 | } 115 | ``` 116 | 117 | For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation) 118 | 119 | ## Adding a new blog post 120 | 121 | 1. Make sure there is a header link to your blog in `website/siteConfig.js`: 122 | 123 | `website/siteConfig.js` 124 | ```javascript 125 | headerLinks: [ 126 | ... 127 | { blog: true, label: 'Blog' }, 128 | ... 129 | ] 130 | ``` 131 | 132 | 2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`: 133 | 134 | `website/blog/2018-05-21-New-Blog-Post.md` 135 | 136 | ```markdown 137 | --- 138 | author: Frank Li 139 | authorURL: https://twitter.com/foobarbaz 140 | authorFBID: 503283835 141 | title: New Blog Post 142 | --- 143 | 144 | Lorem Ipsum... 145 | ``` 146 | 147 | For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) 148 | 149 | ## Adding items to your site's top navigation bar 150 | 151 | 1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: 152 | 153 | `website/siteConfig.js` 154 | ```javascript 155 | { 156 | headerLinks: [ 157 | ... 158 | /* you can add docs */ 159 | { doc: 'my-examples', label: 'Examples' }, 160 | /* you can add custom pages */ 161 | { page: 'help', label: 'Help' }, 162 | /* you can add external links */ 163 | { href: 'https://github.com/facebook/Docusaurus', label: 'GitHub' }, 164 | ... 165 | ], 166 | ... 167 | } 168 | ``` 169 | 170 | For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation) 171 | 172 | ## Adding custom pages 173 | 174 | 1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: 175 | 1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: 176 | 177 | `website/siteConfig.js` 178 | ```javascript 179 | { 180 | headerLinks: [ 181 | ... 182 | { page: 'my-new-custom-page', label: 'My New Custom Page' }, 183 | ... 184 | ], 185 | ... 186 | } 187 | ``` 188 | 189 | For more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages). 190 | 191 | # Full Documentation 192 | 193 | Full documentation can be found on the [website](https://docusaurus.io/). 194 | -------------------------------------------------------------------------------- /website/blog/2016-03-11-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blog Title 3 | author: Blog Author 4 | authorURL: http://twitter.com/ 5 | authorFBID: 100002976521003 6 | --- 7 | 8 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus elementum massa eget nulla aliquet sagittis. Proin odio tortor, vulputate ut odio in, ultrices ultricies augue. Cras ornare ultrices lorem malesuada iaculis. Etiam sit amet libero tempor, pulvinar mauris sed, sollicitudin sapien. 9 | 10 | 11 | 12 | Mauris vestibulum ullamcorper nibh, ut semper purus pulvinar ut. Donec volutpat orci sit amet mauris malesuada, non pulvinar augue aliquam. Vestibulum ultricies at urna ut suscipit. Morbi iaculis, erat at imperdiet semper, ipsum nulla sodales erat, eget tincidunt justo dui quis justo. Pellentesque dictum bibendum diam at aliquet. Sed pulvinar, dolor quis finibus ornare, eros odio facilisis erat, eu rhoncus nunc dui sed ex. Nunc gravida dui massa, sed ornare arcu tincidunt sit amet. Maecenas efficitur sapien neque, a laoreet libero feugiat ut. 13 | 14 | Nulla facilisi. Maecenas sodales nec purus eget posuere. Sed sapien quam, pretium a risus in, porttitor dapibus erat. Sed sit amet fringilla ipsum, eget iaculis augue. Integer sollicitudin tortor quis ultricies aliquam. Suspendisse fringilla nunc in tellus cursus, at placerat tellus scelerisque. Sed tempus elit a sollicitudin rhoncus. Nulla facilisi. Morbi nec dolor dolor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras et aliquet lectus. Pellentesque sit amet eros nisi. Quisque ac sapien in sapien congue accumsan. Nullam in posuere ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin lacinia leo a nibh fringilla pharetra. 15 | 16 | Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin venenatis lectus dui, vel ultrices ante bibendum hendrerit. Aenean egestas feugiat dui id hendrerit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur in tellus laoreet, eleifend nunc id, viverra leo. Proin vulputate non dolor vel vulputate. Curabitur pretium lobortis felis, sit amet finibus lorem suscipit ut. Sed non mollis risus. Duis sagittis, mi in euismod tincidunt, nunc mauris vestibulum urna, at euismod est elit quis erat. Phasellus accumsan vitae neque eu placerat. In elementum arcu nec tellus imperdiet, eget maximus nulla sodales. Curabitur eu sapien eget nisl sodales fermentum. 17 | 18 | Phasellus pulvinar ex id commodo imperdiet. Praesent odio nibh, sollicitudin sit amet faucibus id, placerat at metus. Donec vitae eros vitae tortor hendrerit finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque vitae purus dolor. Duis suscipit ac nulla et finibus. Phasellus ac sem sed dui dictum gravida. Phasellus eleifend vestibulum facilisis. Integer pharetra nec enim vitae mattis. Duis auctor, lectus quis condimentum bibendum, nunc dolor aliquam massa, id bibendum orci velit quis magna. Ut volutpat nulla nunc, sed interdum magna condimentum non. Sed urna metus, scelerisque vitae consectetur a, feugiat quis magna. Donec dignissim ornare nisl, eget tempor risus malesuada quis. 19 | -------------------------------------------------------------------------------- /website/blog/2017-04-10-blog-post-two.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: New Blog Post 3 | author: Blog Author 4 | authorURL: http://twitter.com/ 5 | authorFBID: 100002976521003 6 | --- 7 | 8 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus elementum massa eget nulla aliquet sagittis. Proin odio tortor, vulputate ut odio in, ultrices ultricies augue. Cras ornare ultrices lorem malesuada iaculis. Etiam sit amet libero tempor, pulvinar mauris sed, sollicitudin sapien. 9 | 10 | 11 | 12 | Mauris vestibulum ullamcorper nibh, ut semper purus pulvinar ut. Donec volutpat orci sit amet mauris malesuada, non pulvinar augue aliquam. Vestibulum ultricies at urna ut suscipit. Morbi iaculis, erat at imperdiet semper, ipsum nulla sodales erat, eget tincidunt justo dui quis justo. Pellentesque dictum bibendum diam at aliquet. Sed pulvinar, dolor quis finibus ornare, eros odio facilisis erat, eu rhoncus nunc dui sed ex. Nunc gravida dui massa, sed ornare arcu tincidunt sit amet. Maecenas efficitur sapien neque, a laoreet libero feugiat ut. 13 | 14 | Nulla facilisi. Maecenas sodales nec purus eget posuere. Sed sapien quam, pretium a risus in, porttitor dapibus erat. Sed sit amet fringilla ipsum, eget iaculis augue. Integer sollicitudin tortor quis ultricies aliquam. Suspendisse fringilla nunc in tellus cursus, at placerat tellus scelerisque. Sed tempus elit a sollicitudin rhoncus. Nulla facilisi. Morbi nec dolor dolor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras et aliquet lectus. Pellentesque sit amet eros nisi. Quisque ac sapien in sapien congue accumsan. Nullam in posuere ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin lacinia leo a nibh fringilla pharetra. 15 | 16 | Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin venenatis lectus dui, vel ultrices ante bibendum hendrerit. Aenean egestas feugiat dui id hendrerit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur in tellus laoreet, eleifend nunc id, viverra leo. Proin vulputate non dolor vel vulputate. Curabitur pretium lobortis felis, sit amet finibus lorem suscipit ut. Sed non mollis risus. Duis sagittis, mi in euismod tincidunt, nunc mauris vestibulum urna, at euismod est elit quis erat. Phasellus accumsan vitae neque eu placerat. In elementum arcu nec tellus imperdiet, eget maximus nulla sodales. Curabitur eu sapien eget nisl sodales fermentum. 17 | 18 | Phasellus pulvinar ex id commodo imperdiet. Praesent odio nibh, sollicitudin sit amet faucibus id, placerat at metus. Donec vitae eros vitae tortor hendrerit finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque vitae purus dolor. Duis suscipit ac nulla et finibus. Phasellus ac sem sed dui dictum gravida. Phasellus eleifend vestibulum facilisis. Integer pharetra nec enim vitae mattis. Duis auctor, lectus quis condimentum bibendum, nunc dolor aliquam massa, id bibendum orci velit quis magna. Ut volutpat nulla nunc, sed interdum magna condimentum non. Sed urna metus, scelerisque vitae consectetur a, feugiat quis magna. Donec dignissim ornare nisl, eget tempor risus malesuada quis. 19 | -------------------------------------------------------------------------------- /website/blog/2017-09-25-testing-rss.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Adding RSS Support - RSS Truncation Test 3 | author: Eric Nakagawa 4 | authorURL: http://twitter.com/ericnakagawa 5 | authorFBID: 661277173 6 | --- 7 | 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 8 | 9 | This should be truncated. 10 | 11 | This line should never render in XML. 12 | -------------------------------------------------------------------------------- /website/blog/2017-09-26-adding-rss.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Adding RSS Support 3 | author: Eric Nakagawa 4 | authorURL: http://twitter.com/ericnakagawa 5 | authorFBID: 661277173 6 | --- 7 | 8 | This is a test post. 9 | 10 | A whole bunch of other information. 11 | -------------------------------------------------------------------------------- /website/blog/2017-10-24-new-version-1.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: New Version 1.0.0 3 | author: Eric Nakagawa 4 | authorURL: http://twitter.com/ericnakagawa 5 | authorFBID: 661277173 6 | --- 7 | 8 | This blog post will test file name parsing issues when periods are present. 9 | -------------------------------------------------------------------------------- /website/core/Footer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const React = require('react'); 9 | 10 | class Footer extends React.Component { 11 | docUrl(doc, language) { 12 | const baseUrl = this.props.config.baseUrl; 13 | const docsUrl = this.props.config.docsUrl; 14 | const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; 15 | const langPart = `${language ? `${language}/` : ''}`; 16 | return `${baseUrl}${docsPart}${langPart}${doc}`; 17 | } 18 | 19 | pageUrl(doc, language) { 20 | const baseUrl = this.props.config.baseUrl; 21 | return baseUrl + (language ? `${language}/` : '') + doc; 22 | } 23 | 24 | render() { 25 | return ( 26 |
27 |
{this.props.config.copyright}
28 |
29 | ); 30 | } 31 | } 32 | 33 | module.exports = Footer; 34 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "examples": "docusaurus-examples", 4 | "start": "docusaurus-start", 5 | "build": "docusaurus-build", 6 | "publish-gh-pages": "docusaurus-publish", 7 | "write-translations": "docusaurus-write-translations", 8 | "version": "docusaurus-version", 9 | "rename-version": "docusaurus-rename-version" 10 | }, 11 | "devDependencies": { 12 | "docusaurus": "^1.11.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /website/pages/en/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const React = require('react'); 9 | 10 | const CompLibrary = require('../../core/CompLibrary.js'); 11 | 12 | const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */ 13 | const Container = CompLibrary.Container; 14 | const GridBlock = CompLibrary.GridBlock; 15 | 16 | class HomeSplash extends React.Component { 17 | render() { 18 | const {siteConfig, language = ''} = this.props; 19 | const {baseUrl, docsUrl} = siteConfig; 20 | const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; 21 | const langPart = `${language ? `${language}/` : ''}`; 22 | const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; 23 | 24 | const SplashContainer = props => ( 25 |
26 |
27 |
{props.children}
28 |
29 |
30 | ); 31 | 32 | const Logo = props => ( 33 |
34 | Project Logo 35 |
36 | ); 37 | 38 | const ProjectTitle = () => ( 39 |

40 | {siteConfig.title} 41 | {siteConfig.tagline} 42 |

43 | ); 44 | 45 | const PromoSection = props => ( 46 |
47 |
48 |
{props.children}
49 |
50 |
51 | ); 52 | 53 | const Button = props => ( 54 |
55 | 56 | {props.children} 57 | 58 |
59 | ); 60 | 61 | return ( 62 | 63 | 64 |
65 | 66 | 67 | 68 | 69 | 70 |
71 |
72 | ); 73 | } 74 | } 75 | 76 | class Index extends React.Component { 77 | render() { 78 | const {config: siteConfig, language = ''} = this.props; 79 | const {baseUrl} = siteConfig; 80 | 81 | const Block = props => ( 82 | 86 | 91 | 92 | ); 93 | 94 | const Description = () => ( 95 | 96 | {[ 97 | { 98 | content: 99 | 'This project meant to be a recompilation of documentations for rails and common realted projects as devise, rspec, factory bot and others.', 100 | image: `${baseUrl}img/undraw_code_review.svg`, 101 | imageAlign: 'right', 102 | title: 'Description', 103 | }, 104 | ]} 105 | 106 | ); 107 | 108 | return ( 109 |
110 | 111 |
112 | 113 |
114 |
115 | ); 116 | } 117 | } 118 | 119 | module.exports = Index; 120 | -------------------------------------------------------------------------------- /website/sidebars.json: -------------------------------------------------------------------------------- 1 | { 2 | "rails": { 3 | "Start Here": [ 4 | "rails/getting-started", 5 | "rails/development-dependencies-install" 6 | ], 7 | "Models": [ 8 | "rails/active-record-basics", 9 | "rails/active-record-migrations", 10 | "rails/active-record-validations", 11 | "rails/active-record-callbacks", 12 | "rails/active-record-associations", 13 | "rails/active-record-query", 14 | "rails/multiple-databases", 15 | "rails/active-record-postgresql" 16 | ], 17 | "Views": [ 18 | "rails/layouts-and-rendering", 19 | "rails/action-view", 20 | "rails/action-view-form-helpers" 21 | ], 22 | "Controllers": [ 23 | "rails/action-controller", 24 | "rails/rails-routing" 25 | ], 26 | "Other Components": [ 27 | "rails/active-support-core", 28 | "rails/active-support-instrumentation", 29 | "rails/action-mailer", 30 | "rails/action-mailbox", 31 | "rails/active-model", 32 | "rails/active-job", 33 | "rails/action-text", 34 | "rails/active-storage", 35 | "rails/action-cable" 36 | ], 37 | "Digging Deeper": [ 38 | "rails/rails-i18n", 39 | "rails/testing-rails", 40 | "rails/securing-rails", 41 | "rails/debugging-rails", 42 | "rails/configuring-rails", 43 | "rails/rails-command-line", 44 | "rails/asset-pipeline", 45 | "rails/working-with-javascript", 46 | "rails/autoloading-and-reloading", 47 | "rails/caching-with-rails", 48 | "rails/api-only-apps", 49 | "rails/threading", 50 | "rails/initialization", 51 | "rails/engines" 52 | ], 53 | "Extending Rails": [ 54 | "rails/rails-on-rack", 55 | "rails/generators-&-templates", 56 | "rails/application-templates", 57 | "rails/creating-rails-plugins" 58 | ], 59 | "Contributions": [ 60 | "rails/contributing-to-rails", 61 | "rails/api-documentation", 62 | "rails/guides-guidelines" 63 | ], 64 | "Policies": ["rails/maintenance-policy"] 65 | }, 66 | "devise": { 67 | "General": [ 68 | "devise/overview", 69 | "devise/starting-with-rails" 70 | ], 71 | "Getting Started": [ 72 | "devise/installation", 73 | "devise/controller-filters-and-helpers", 74 | "devise/configuring-models", 75 | "devise/strong-parameters", 76 | "devise/configuring-views", 77 | "devise/configuring-controllers", 78 | "devise/configuring-routes" 79 | ], 80 | "Advanced Topics": [ 81 | "devise/i18n", 82 | "devise/test-helpers", 83 | "devise/omniauth", 84 | "devise/configuring-multiple-models", 85 | "devise/activejob-integration", 86 | "devise/password-reset-tokens-and-rails-logs", 87 | "devise/other-orms", 88 | "devise/rails-api-mode" 89 | ], 90 | "Guides": [ 91 | "devise/guides-list" 92 | ], 93 | "Project": [ 94 | "devise/extensions", 95 | "devise/example-applications", 96 | "devise/contributing", 97 | "devise/bug-reports", 98 | "devise/additional-information" 99 | ] 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /website/siteConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | // See https://docusaurus.io/docs/site-config for all the possible 9 | // site configuration options. 10 | 11 | // List of projects/orgs using your project for the users page. 12 | const users = [ 13 | { 14 | caption: 'User1', 15 | // You will need to prepend the image path with your baseUrl 16 | // if it is not '/', like: '/test-site/img/image.jpg'. 17 | image: '/img/undraw_open_source.svg', 18 | infoLink: 'https://www.facebook.com', 19 | pinned: true, 20 | }, 21 | ]; 22 | 23 | const siteConfig = { 24 | title: 'Rails Setup', // Title for your website. 25 | tagline: 'Documentation for Rails and related libraries', 26 | url: 'https://HenryTabima.github.io', // Your website URL 27 | baseUrl: '/rails-setup/', // Base URL for your project */ 28 | projectName: 'rails-setup', 29 | organizationName: 'HenryTabima', 30 | // For top-level user or org sites, the organization is still the same. 31 | // e.g., for the https://JoelMarcey.github.io site, it would be set like... 32 | // organizationName: 'JoelMarcey' 33 | 34 | // For no header links in the top nav bar -> headerLinks: [], 35 | headerLinks: [ 36 | {doc: 'rails/getting-started', label: 'Rails'}, 37 | {doc: 'devise/overview', label: 'Devise'}, 38 | {href: 'https://github.com/HenryTabima/rails-setup', label: 'GitHub'} 39 | ], 40 | 41 | // If you have users set above, you add it here: 42 | users, 43 | 44 | /* path to images for header/footer */ 45 | headerIcon: 'img/favicon.ico', 46 | footerIcon: 'img/favicon.ico', 47 | favicon: 'img/favicon.ico', 48 | 49 | /* Colors for website */ 50 | colors: { 51 | primaryColor: '#C5333B', 52 | secondaryColor: '#444', 53 | }, 54 | 55 | /* Custom fonts for website */ 56 | /* 57 | fonts: { 58 | myFont: [ 59 | "Times New Roman", 60 | "Serif" 61 | ], 62 | myOtherFont: [ 63 | "-apple-system", 64 | "system-ui" 65 | ] 66 | }, 67 | */ 68 | 69 | // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds. 70 | copyright: `Rails Setup ${new Date().getFullYear()}`, 71 | 72 | highlight: { 73 | // Highlight.js theme to use for syntax highlighting in code blocks. 74 | theme: 'default', 75 | }, 76 | 77 | docsSideNavCollapsible: true, 78 | 79 | // Add custom scripts here that would be placed in