Affichage des articles dont le libellé est ruby on rails. Afficher tous les articles
Affichage des articles dont le libellé est ruby on rails. Afficher tous les articles

vendredi 17 juin 2011

Hébergement node.js avec Heroku Celadon Cedar Stack

Le service PaaS Heroku a lancé il y a peu de temps en beta publique sa nouvelle stack, Celadon Cedar.

Une des nouveautés apportée par cette version est le support de node.js, framework destiné à développer des applications réseau facilement scalables en JavaScript (du côté serveur), utilisant la machine virtuelle V8.

Installation de heroku

$ gem install heroku

Application basique

On va écrire une application la plus simple possible, le but n'étant pas d'apprendre le node.js, donc un "hello world" fera parfaitement l'affaire.
var express = require('express');

var app = express.createServer(express.logger());

app.get('/', function(request, response) {
  response.send('Hello World!');
});

var port = process.env.PORT || 3000;
app.listen(port, function(){
  console.log("Listening on " + port);
});

Utilisation de npm

Cedar reconnait une app node.js si il y a un fichier package.json, donc même si l'application n'a pas de dépendance, il faut inclure ce fichier.

{
  "name": "node-example",
  "version": "0.0.1",
  "dependencies": {
    "express": "2.2.0"
  }
}

Il est préférable de ne pas déployer le fichier node_modules, donc ajoutons le au .gitignore.

Déclaration des "process types" with Foreman/Procfile

Pour exécuter l'application, nous devons déclarer la commande à utiliser pour la lancer, donc simplement lancer notre script.

Dans le fichier Procfile :

web: node web.js

On peut donc maintenant lancer l'appli avec Foreman

$ gem install foreman
$ foreman start
14:39:04 web.1     | started with pid 24384
14:39:04 web.1     | Listening on 5000

L'application est donc accessible sur le port 5000.

Déploiement

Heroku nécessitant git, la première chose à faire est de versionner l'application :
$ git init
Initialized empty Git repository in .git/
$ git add .
$ git commit -m "new app"
Created initial commit 5df2d09: new app

Ensuite, il faut créer l'application Heroku sur la plateforme, via l'api en ligne de commande :
$ heroku create --stack cedar
Creating radiant-river-296... done, stack is cedar
http://radiant-river-296.herokuapp.com/ | git@heroku.com:radiant-river-296.git
Git remote heroku added

Une application appname vierge nous attend donc chez Heroku, il suffit de pousser notre application avec git pour la voir en ligne immédiatement :
$ git push heroku master
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 923 bytes, done.
Total 9 (delta 2), reused 0 (delta 0)

-----> Heroku receiving push
-----> Node.js app detected
-----> Vendoring node 0.4.7
-----> Installing dependencies with npm 1.0.6
       mime@1.2.2 ./node_modules/express/node_modules/mime
       connect@1.4.1 ./node_modules/express/node_modules/connect
       qs@0.1.0 ./node_modules/express/node_modules/qs
       express@2.1.0 ./node_modules/express
       Dependencies installed
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 3.1MB
-----> Launching... done, v4
       http://radiant-river-296.herokuapp.com deployed to Heroku

To git@heroku.com:radiant-river-296.git
 * [new branch]      master -> master

Avant de voir notre application en ligne, il faut la scaler :
Before looking at the app on the web, we’ll need to scale the web process:

$ heroku ps:scale web=1
Scaling web processes... done, now running 1
Now, let’s check the state of the app’s processes:

$ heroku ps
Process       State               Command
------------  ------------------  --------------------------------------------
web.1         up for 10s          node web.js
The web process is up. Review the logs for more information:

$ heroku logs
2011-03-10T10:22:30-08:00 heroku[web.1]: State changed from created to starting
2011-03-10T10:22:32-08:00 heroku[web.1]: Running process with command: `node web.js`
2011-03-10T10:22:33-08:00 heroku[web.1]: Listening on 18320
2011-03-10T10:22:34-08:00 heroku[web.1]: State changed from starting to up

Tout est ok, notre app est accessible, on peut l'ouvrir via un simple heroku open.

mercredi 30 mars 2011

Déploiement et hébergement Ruby on Rails sur Heroku

Heroku

Heroku est un hébergeur Ruby on Rails dans le cloud en mode PAAS (Platform As A Service). C'est de très loin la façon la plus simple pour déployer et héberger des applications Ruby on Rails. L'hébergement est gratuit pour les sites à faible trafic, y compris pour la base de données et de nombreux addons, mais est également très scalable.

Fonctionnement

La publication de votre application sur la plateforme Heroku se fait via git.
Heroku propose une api très complète de gestion de votre application, utilisable en ligne de comande :
  • Consultation des logs
  • Gestion des utilsateurs
  • Tâches Rake
La grande force d'Heroku sont la grande quantitié d'addons disponibles, la plupart gratuits pour une utilisation basique.
  • MongoDB via MongoHQ : Gratuit jusqu'à 16Mo
  • CouchDB via Cloudant : Gratuit jusqu'à 250Mo.
  • Redis via Redis To Go : Gratuit jusqu'à 5Mo, sans persistance.
  • Solr : payant, à partir de 20$.
  • ...

Installation de la gem Heroku
Ensuite, pour pouvoir utiliser Heroku dans votre application Rails, ajoutez la gem à votre fichier Gemfile :
source 'http://rubygems.org'
gem 'rails', '3.0.3'
gem "heroku"

Utilisation

Mise en place de Git
Heroku nécessitant git, la première chose à faire est de versionner votre application :
$ git init
Initialized empty Git repository in .git/
$ git add .
$ git commit -m "new app"
Created initial commit 5df2d09: new app

Evidemment, Heroku va avoir besoin de notre clef publique pour pouvoir accepter les push, il faut donc les générer si ce n'est pas déjà fait, sinon simplement les ajouter :
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
$ heroku keys:add
Uploading ssh public key /home/joe/.ssh/id_rsa.pub

Déploiement de l'application
Ensuite, il faut créer l'application Heroku sur la plateforme, via l'api en ligne de commande :
$ heroku create appname
Enter your Heroku credentials.
Email: joe@doe.com
Password: 
Uploading ssh public key /home/joe/.ssh/id_rsa.pub
Created http://appname.heroku.com/ | git@heroku.com:appname.git
Git remote heroku added

Une application appname vierge nous attend donc chez Heroku, il suffit de pousser notre application avec git pour la voir en ligne immédiatement :
$ git push heroku master
Counting objects: 65, done.
Compressing objects: 100% (58/58), done.
Writing objects: 100% (65/65), 80.54 KiB, done.
Total 65 (delta 14), reused 0 (delta 0)

----- Heroku receiving push
----- Rails app detected
       Compiled slug size is 0.1MB
----- Launching....... done
       App deployed to Heroku

To git@heroku.com:appname.git
   3b3ed7c..350b521  master -> master

Si notre application utilise une base de données, il est possible de la bootstrapper directement :
$ heroku rake db:migrate
$ heroku rake db:seed

Mise à jour
Lors des prochaines mise à jour de notre application, tout ce que nous aurons à faire est :
$ git push heroku master

Conclusion

Avec Heroku, vous avez donc la possibilité de mettre en ligne en quelques secondes une application Ruby on Rails, avec un grand nombre d'addons vous permettant d'avoir une base application très solide : par exemple une stack Ruby on Rails / MongoDB / Redis / SOLR.

mercredi 15 décembre 2010

Réaliser un blog avec Ruby On Rails 3 et MongoDB

Objectifs

Le but de cet article est assez simple : réaliser un moteur de blog (minimaliste) en utilisant Ruby on Rails 3 et MongoDB.

Installation

Parce qu'il faut bien commencer quelque part, on va installer notre environnement. L'installation détaillée ici est pour ubuntu 10.10.
On va utiliser rvm (Ruby Version Manager), qui permet de gérer facilement plusieurs version de Ruby simultanément.

On commence par installer git, qui nous sera utile tout au long du projet, notamment pour l'installation de certaines gems, ou encore pour le déploiement.
sudo apt-get install git-core

Puis les dépendance nécessaires pour compiler ruby.

sudo apt-get install build-essential bison openssl libreadline5 libreadline5-dev curl git-core zlib1g zlib1g-dev libssl-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libmysqlclient-dev libreadline-dev

Ensuite on installe la dernière version de rvm en suivant la doc officielle :
# RVM install
bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

# Load RVM into shell
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"' >> ~/.bashrc

# RVM bash completion complete
echo '[[ -r $rvm_path/scripts/completion ]] && . $rvm_path/scripts/completion' >> ~/.bashrc

# One-time source of RVM
source ~/.rvm/scripts/rvm

rvm est installé, on peut maintenant compiler et installer ruby :

rvm install 1.9.2
rvm use 1.9.2 --default

On a maintenant un environnement ruby à jour est prêt à être utilisé.

Initialisation du projet

On va tout d'abord créer le squelette de l'application grace à rails (avec les flags qui vont bien -O pour desactver ActiveRecord, -J pour utilier jquery, -T pour ne pas générer les Tests/
rails new MongoOnRailsBlog -O -J -T

Notre application rails est en place, on peut déjà voir le résultat en lancant
rails server

Et en visitant l'adresse http://localhost:3000.

Par défaut, rails va utiliser sqlite comme backend, et nous voulons utiliser mongodb. Pour cela, on va utiliser MongoID, un ORM pour MongoDB.

On va l'installer via bundle, en modifiant le fichier GemFile
source 'http://rubygems.org'

gem 'rails', '3.0.3'

gem "mongoid", ">= 2.0.0.beta.20"
gem "bson_ext"

gem "will_paginate"

gem "devise"

gem "haml", ">= 3.0.0"
gem "haml-rails", :group => :development
gem "ruby_parser", :group => :development
gem "hpricot", :group => :development
gem "formtastic"
gem "jquery-rails"

gem "heroku"

Et en lancant un
bundle install

On commence par un peu de configuration, pour que les générateurs nous machent le travail pour MongoId et pour haml.
application.rb
# Configure generators
config.generators do |g|
  g.orm :mongoid
  g.template_engine :haml
end

rails generate mongoid:config
rails devise:install
rails generate jquery:install
rails generate formtastic:install 

Code


Les articles
Les articles sont bien entendu au centre de notre moteur de blog, ils correspondront à une collection MongoDB à part entière.

Un article possède donc :
  • Un slug (l'url SEO Friendly), qui nous servira d'identifiant
  • Un titre
  • Un contenu
  • Une date de publication et d'édition
  • Un auteur (facultatif)
  • Des tags
  • Des commentaires

Pour les champs "complexes" (auteur, tags, commentaires), plusieurs solutions s'offrent à nous.
  • Pour les tags, la solution la plus simple est un tableau, largement suffisant dans la mesure où le tag est une simple chaîne de caractères
  • Les commentaires sont fortement liés à un document, et n'ont aucun sens sans eux, la meilleure solution est donc de les embarquer dans l'article : voir la doc de MongoId sur les associations.
  • Pour les auteurs, le choix est plus compliqué. On peut aussi embarquer l'auteur dans l'article, ce qui sera plus performant, mais nécessitera de mettre à jour tous les articles d'une personne si par exemple elle change son nom. On va ici ne stocker qu'une référence à l'auteur dans l'article, ce qui est moins performant, mais sera plus rapide à implémenter : voir la doc de MongoId sur les associations.

On va commence par générer le squelette pour la gestion des articles grace au scaffold, ce qui à le grand avantage de faire gagner du temps sur l'écriture des controlleurs, vues, ... :
rails g scaffold article slug:string title:string body:text published_date:date
On complète bien sur notre modèle :
class Article
  include Mongoid::Document
  include Mongoid::Timestamps
  
  field :slug, :type => String
  field :title, :type => String
  field :body, :type => String
  field :published_at, :type => DateTime
  field :edited_at, :type => DateTime
  field :tags, :type => Array
  
  referenced_in :user, :stored_as => :array, :inverse_of => :articles
  embeds_many :comments

  key :slug

  before_save :set_edited_date
  before_create :set_slug,:set_published_date
  
  def set_published_date
    self.published_at = DateTime.now
  end
  
  def set_edited_date
    self.edited_at = DateTime.now
  end

  def set_slug
    self.slug = "#{title.parameterize}"
  end

  validates_presence_of :title, :body
  validates_uniqueness_of :slug

  index [[:published_date, Mongo::DESCENDING]]
  index :tags
  index :user

end

Comme on peut le voir, on complexifie un peu notre modèle pour mettre automatiquement les dates de publication et d'édition (notez que ces dates font doublons avec les Mongoid::Timestamps), et générer automatiquement le slug.

On peut donc déjà s'amuser à créer un article via la console rails :
ruby-1.9.2-p0 > Article.create(:title => "My First Post", :body => "blablabla", :tags => ["misc"])
 => #

Les commentaires étant imbriqués dans les articles, le formulaire de saisie de commentaire sera affiché sur la page de vue d'un article :
resources :articles do
  resources :comments
end

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])

    respond_to do |format|
      format.html
      format.xml  { render :xml => @article }
    end
  end
end

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create!(params[:comment])
    redirect_to @article, :notice => "Commented!"
  end
end

%h1 New Comment
= semantic_form_for [@article, Comment.new] do |f|
  = f.inputs do
    = f.input :title
    = f.input :body, :as => :text
  = f.buttons do
    = f.commit_button

On va maintenant ajouter à notre blog un nuage de tag, et on va pour cela utiliser le map-reduce intégrer à MongoDB :

class Article
  def self.tag_cloud
    map = <<EOF
      function() {
        for (index in this.tags) {
          emit(this.tags[index],1);
        }
      }
EOF
    reduce = <<EOF
      function(previous, current) {
        var count = 0;
        for (index in current) {
          count += current[index]
        }
        return count;
      }
EOF
    if Mongoid.master.collection(collection.name).count != 0
      collection.map_reduce(map,reduce).find()
    else
      []
    end
  end
end
Et pour l'afficher :
%ul.tagcloud
  - Article.tag_cloud.each do |tag|
    %li{:style => "font-size: #{tag['value']}em"}
      %a{:href => "#"}
        = link_to tag["_id"], articles_by_tag_path(tag["_id"])

On a donc déjç, en seulement 1h de développement, un blog où l'on peut poster, mettre des commentaires, et naviguer par tag.

On va maintenant ajouter la notion d'auteur sur les articles et les commentaires, et on va pour cela utiliser Devise
rails generate devise User
rails generate devise:views users

Devise a le grand avantage de s'occuper de tout le côté inscription, authentification récupération de mot de passe, ... pour nous.

Il suffit pour cela d'ajouter dans le routes.rb :
devise_for :users
Et les URLs /users/sign_up, /users/sign_in, /users/sign_out sont disponibles.

On peut donc mantenant lié un article et un commentaire à un utilisateur, en modifiant le controller de création.

class ArticlesController < ApplicationController
  def create
    params[:article][:tags] = params[:article][:tags].split(',')
    @article = Article.new(params[:article])
    if user_signed_in?
      @article.user = current_user
    end
    respond_to do |format|
      if @article.save
        format.html { redirect_to(@article, :notice => 'Article was successfully created.') }
        format.xml  { render :xml => @article, :status => :created, :location => @article }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @article.errors, :status => :unprocessable_entity }
      end
    end
  end
end

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    if user_signed_in?
      params[:comment][:user] = current_user
    end
    @comment = @article.comments.create!(params[:comment])
    redirect_to @article, :notice => "Commented!"
  end
end

Grace à un simple plugin, et à la puissance de rails, il nous a fallu moins d'une heure pour mettre en place un système d'authentification complet sur notre application. On peut même ajouter les fonctionnalité d'affichage de l'auteur d'un article, ou la liste des articles d'un auteur :
class ArticlesController < ApplicationController
  def author
    @author = User.find(params[:author])
    @articles = @author.articles.desc(:published_at)
    respond_to do |format|
      format.html
      format.xml  { render :xml => @articles }
    end
  end
end

Mise en ligne
Pour déployer notre blog, nous allons utiliser la plateforme d'hébergement cloud pour Ruby on Rails Heroku, qui permet de déployer très facilement et gratuitement une application rails, avec à disposition un grand nombre d'addon, dont MongoDB.

Il suffit de s'inscrire sur le site, et ensuite d'installer la gem heroku via bundler.

Je vous invite à lire la documentation d'heroku.

Une fois le déploiement fait via git, l'application est tout de suite visible en ligne via
http://mongoonrailsblog.heroku.com/.

Le code source est disponible sur github.

Voila, c'est la fin de mon premier essai en Ruby on Rails, qui m'a permis de construire un moteur de blog très minimaliste en quelques heures seulement, et de le mettre en ligne.