Semaine 4

L'objectif de la semaine est de mettre en place le projet de base pour permettre à chacun de développer efficacement son module de l'application:

Mise en place

Votre répertoire git doit posséder cette structure (sensible à la case): Vos projets rails et angular doivent ABSOLUMENT être à la racine de ces répertoires.

Rails en mode API

rails new projet -d mysql --api
Controlleur API
class ApplicationController < ActionController::API

end
ActionController::API remplace ActionController::Base puisqu'il est plus restreint dans l'utilisation d'un API. Il ne contient pas de helper ou autre module utile uniquement dans le html

Intégrer Angular

Pour configurer votre environnement de développement front-end, vous devez utiliser Rails pour servir votre page Angular. Rails Route de type 'wildcard', Ce fichier de route est analysé de haut en bas
Rails.application.routes.draw do
  devise_for :users, controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations'
  }
  root to: "angular#index"
  namespace :api, constraints: { format: 'json' }  do
    resources :todos
  end

  match '*url', to: "angular#index", via: :get # le parametre url contiendra tout ce qui suit l'étoile dans l'url
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
Quelques points sont à ajuster afin de permettre à devise de s'adapter au paradigme de l'api. Un controlleur de gestion static Permet de retourner le contenu angular lorsqu'une route hors api est applée pour la navigation sur le navigateur index.html sera votre contenu compilé angular
class AngularController < ActionController::Base
    def index
        render file: "public/index.html", layout: false
    end
end
Angular

Devise en mode API

Devise permet l'ajout de comportement d'échec personnalisé Ajout du répertoire lib à l'intérieur du Framework Rails À l'intérieur de la classe Application config/application.rb
config.autoload_paths << "#{Rails.root}/lib"
Définition du comportement lib/custom_failure.rb
class CustomFailure < Devise::FailureApp
    def respond
        self.status = 401
        self.content_type = 'json'
        self.response_body = {"errors" => ["Invalid login credentials"]}.to_json
    end
end
Ajout de la classe à l'intérieur de Devise config/initializers/devise.rb
config.warden do |manager|
  manager.failure_app = CustomFailure
end
Éviter que devise envoi des messages html dans la session Ajoutez cette configuration dans: config/initializers/devise.rb
config.navigational_formats = ['/']
Ajout de la session dans le cookie config/application.rb
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
Changement de l'ordre d'analyse des routes Dans angular on crée une route dite "trap all" qui va capter également les routes des fichiers statics. on redéfini l'ordre d'analyse pour valider s'il s'agit d'une route de fichier provenant du ActiveStorage avant notre application. config/application.rb
config.railties_order = [ActiveStorage::Engine, :main_app, :all]
Les réponses de la session et création d'un usager
rails generate devise:controllers users -c=sessions
rails generate devise:controllers users -c=registrations
Utiliser le code du source pour réécrire les fonctions à notre convenance Ex. pour un login https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb: app/controllers/users/sessions_controller.rb
def create
    self.resource = warden.authenticate!(auth_options)
    sign_in(resource_name, resource)
    render json: {success: true, email: resource.email}
end
Ex. pour un enregistrement source app/controllers/users/registrations_controller.rb
def create
  build_resource(sign_up_params)

  resource.save
  yield resource if block_given?
  if resource.persisted?
    if resource.active_for_authentication?
      #set_flash_message! :notice, :signed_up
      sign_up(resource_name, resource)
      render json: {success: true, email: resource.email}
      #respond_with resource, location: after_sign_up_path_for(resource)
    else
      #set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
      expire_data_after_sign_in!

      render json: {success: false, email: resource.email}
      #respond_with resource, location: after_inactive_sign_up_path_for(resource)
    end
  else
    clean_up_passwords resource
    set_minimum_password_length

    render json: {success: false, email: resource.email}
    #respond_with resource
  end
end
Pour obtenir une réponse cohérente lors d'une déconnection, surchargez cette fonction dans app/controllers/users/sessions_controller.rb:
def respond_to_on_destroy
  render json: {success: false}.to_json
end

Déploiement

Serveur web
apt-get install apache2
Installation du module d'interpréation ruby Passenger, https://www.phusionpassenger.com/library/walkthroughs/deploy/ruby/ownserver/apache/oss/bionic/install_passenger.html
apt-get install -y dirmngr gnupg
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
apt-get install -y apt-transport-https ca-certificates
sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bionic main > /etc/apt/sources.list.d/passenger.list'
apt-get update
apt-get install -y libapache2-mod-passenger

a2enmod passenger
apache2ctl restart
Enlever le .conf par défaut (/etc/apache2/site-enabled) Ajouter ce vhost:

    ServerName yourserver.com

    # Tell Apache and Passenger where your app's 'public' directory is
    DocumentRoot /var/www/html/public

    PassengerRuby /path-to-ruby

    # Relax Apache security settings
    
      Allow from all
      Options -MultiViews
      # Uncomment this if you're on Apache >= 2.4:
      #Require all granted
    

Redemarrer le service
apache2ctl restart
Penser aussi à vérifier le mécanisme de mise à jour de l'app déployée: https://www.phusionpassenger.com/library/walkthroughs/deploy/ruby/ownserver/apache/oss/bionic/deploy_app.html