2009-06-12 5 views
0

Je travaille sur un site Web hébergé sur le service en direct de Microsoft Office. Il dispose d'un formulaire de contact permettant aux visiteurs d'entrer en contact avec le propriétaire. Je veux écrire un script Ruby qui se trouve sur un serveur séparé et auquel le formulaire sera POST. Il va analyser les données du formulaire et envoyer les détails par e-mail à une adresse prédéfinie. Le script doit ensuite rediriger le navigateur vers une page de confirmation.POSTing un formulaire HTML à remote.cgi - écrit en Ruby?

J'ai une machine hardy ubuntu qui exécute nginx et postfix. Ruby est installé et nous verrons comment utiliser Thin et sa fonctionnalité Rack pour gérer le script. Maintenant, il est venu à l'écriture du script et j'ai dessiné un blanc.

Cela fait longtemps et si je me souviens bien le processus est quelque chose comme;

  • lecture en-tête HTTP
  • paramètres parse
  • Envoyer email
  • header envoyer redirect

D'une manière générale, la question a été répondu. Déterminer comment utiliser la réponse était plus compliqué que prévu et j'ai pensé que ça valait la peine d'être partagé.

Premiers pas:

j'ai appris assez brusquement que nginx ne supporte pas directement les scripts cgi. Vous devez utiliser un autre processus pour exécuter le script et envoyer nginx aux demandes de proxy. Si je faisais cela en php (qui, à mon avis, aurait été un choix plus naturel), je pourrais utiliser quelque chose comme php-fcgi et s'attendre à ce que la vie soit assez simple. Ruby et fcgi se sentaient plutôt décourageants. Mais si nous abandonnons l'idéal de charger ces choses à l'exécution alors Rack est probablement la solution la plus directe et Thin inclut tout ce dont nous avons besoin. Apprendre à faire de petites applications de base avec eux a été profondément bénéfique pour un nouveau venu Rails comme moi. Les bases d'une application Rails peuvent sembler cachées depuis longtemps et Rack m'a aidé à lever le rideau un peu plus loin. Néanmoins, suivre les conseils de Yehuda et regarder sinatra a été une autre surprise. J'ai maintenant une application basique de sinatra fonctionnant dans une instance mince. Il communique avec nginx sur une socket unix dans ce que je comprends est le moyen standard. Sinatra permet une manière très élégante de gérer différentes demandes et routes dans l'application. Tout ce dont vous avez besoin est un get '/' {} pour commencer à gérer les demandes à l'hôte virtuel. Pour ajouter plus (d'une manière propre) nous incluons juste un routes/script.rb dans le fichier principal.

 
# cgi-bin.rb 
# main file loaded as a sinatra app 

require 'sinatra' 

# load cgi routes 
require 'routes/default' 
require 'routes/contact' 

# 404 behaviour 
not_found do 
    "Sorry, this CGI host does not recognize that request." 
end 

Ces fichiers itinéraire appel à une fonctionnalité stockées dans une bibliothèque de classes séparées:

# routes/contact.rb 
# contact controller 

require 'lib/contact/contactTarget' 
require 'lib/contact/contactPost' 

post '/contact/:target/?' do |target| 
    # the target for the message is taken from the URL 
    msg = ContactPost.new(request, target) 
    redirect msg.action, 302 
end

L'horreur pure de déterminer une chose si simple restera avec moi pendant un certain temps. Je m'attendais à laisser calmement nginx savoir que les fichiers .rb devaient être exécutés et juste continuer avec lui. Maintenant que cette petite application Sinatra est opérationnelle, je serai capable de plonger directement si je veux ajouter des fonctionnalités supplémentaires à l'avenir.

Mise en œuvre:

La classe gère ContactPost l'aspect de la messagerie.Tout ce qu'il faut savoir sont les paramètres dans la demande et la cible pour l'email. ContactPost :: action déclenche tout et renvoie une adresse pour le contrôleur à rediriger vers.

Il existe une classe ContactTarget distincte qui effectue une certaine authentification pour s'assurer que la cible spécifiée accepte les messages provenant de l'URL fournie dans request.referrer. Ceci est géré dans ContactTarget :: accept? comme on peut le deviner à partir de la méthode d'action ContactPost ::;


# lib/contact/contactPost.rb 

class ContactPost 

# ... 

    def action 
    return failed unless @target.accept? @request.referer 
    if send? 
     successful 
    else 
     failed 
    end 
    end 

# ... 

end

ContactPost :: succès et ContactPost :: a échoué chaque retour d'une adresse de redirection en combinant les chemins fournis avec le formulaire HTML avec l'URI request.referer. Tout le comportement est ainsi spécifié dans le formulaire HTML. Les futurs sites Web qui utilisent ce script doivent juste être listés dans le propre ~/cgi/contact.conf de l'utilisateur et ils seront absents. C'est parce que ContactTarget recherche dans /home/:target/cgi/contact.conf pour les détails. Peut-être qu'un jour ce sera inapproprié, mais pour l'instant c'est très bien pour mes objectifs.

La méthode send est assez simple, elle crée une instance d'une simple classe Email et l'expédie. La classe Email est basée sur l'exemple d'utilisation standard donné dans la documentation Ruby net/smtp; Tout ce que j'ai besoin de faire est de mettre l'application en rack, de laisser savoir à nginx à quelle prise parler et nous sommes partis.

Merci à tous pour vos conseils utiles dans la bonne direction! Vive sinatra!

+0

"Ruby est installé et nginx est prêt à exécuter des fichiers ruby ​​sur mon hôte virtuel choisi." Eh bien, je fignais. J'ai juste supposé que ce serait facile, donc je ne voulais pas encombrer la question avec ça. Nginx ne supporte pas directement les CGI. Le support est donné par procuration, généralement à une instance de fcgi, bien que je pense avoir trouvé comment faire travailler Ruby avec Thin donc je vais aller dans cette direction. Jusqu'à présent, cela aurait été plus facile en php! – deau

Répondre

1

Probablement la meilleure façon de le faire serait d'utiliser une bibliothèque Ruby existante comme Sinatra:

require "rubygems" 
require "sinatra" 

get "/myurl" do 
    # params hash available here 
    # send email 
end 

Vous voudrez probablement utiliser MailFactory pour envoyer l'e-mail réelle, mais vous avez certainement pas besoin se débiter avec des en-têtes ou des paramètres d'analyse.

+0

Il s'avère que vous avez raison.Je devrais de toute façon substituer le script à nginx, donc quelque chose comme sinatra peut le résoudre aussi. Je vais essayer de le faire avec Rack through Thin. Merci pour la direction :-) – deau

2

Il est dans le module Net, voici un exemple:

@net = Net::HTTP.new 'http://www.foo.com', 80 
    @params = {:name => 'doris', :email => '[email protected]'} 

    # Create HTTP request 
    req = Net::HTTP::Post.new('script.cgi', {}) 
    req.set_form_data @params 

    # Send request 
    response = @net.start do |http| 
    http.read_timeout = 5600 
    http.request req 
    end 
+0

Merci, il semblerait que j'aurai besoin du module Net pour envoyer l'email mais je ne vois pas comment l'utiliser pour lire les paramètres affichés ou envoyer les en-têtes. Je pense que je suis peut-être trop compliquer. J'ai trouvé que vous pouvez simplement imprimer sur stdout dans un script cgi et envoyer un en-tête de texte pour la redirection. Je chercherai une manière similaire de lire les paramètres donnés dans l'url. Une fois cela fait, je serai parti. – deau

0

classe CGI de Ruby peut être utilisé pour écrire des scripts CGI. Veuillez vérifier: http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/index.html

Par ailleurs, il n'est pas nécessaire de lire l'en-tête HTTP. Les paramètres d'analyse seront faciles en utilisant la classe CGI. Ensuite, envoyez l'e-mail et redirigez.

+0

Bien regarder dans cgi.rb a révélé toutes sortes de choses. Il semble que je n'aurai pas besoin de charger toute la librairie pour faire ce dont j'ai besoin - je pense que cela peut être fait en ligne avec juste quelques lignes de code. Je m'en occuperai plus demain. – deau

Questions connexes