Développeur Web RoR

Aller au contenu | Aller au menu | Aller à la recherche

Tag - rails

Fil des billets

vendredi 7 février 2014

Transformer un array d'objet ActiveRecord en hash avec comme clé l'id et l'objet en valeur

La petite astuce du jour :

Comment transformer un Array d'objet ActiveRecord en Hash avec comme clé l'id et l'objet en valeur ?

Solution

Hash[Family.all.map{ |f| [f.id,f] }]

Ce qui donne : 

{

     4: #<Family id: 4>,

     5: #<Family id: 5>,

     6: #<Family id: 6>,

}

De rien :-)

mardi 21 janvier 2014

Utiliser hstore avec le gem Apartment

Il m'est arrivé d'avoir besoin de hstore (stockage key/value dans postgres) avec Apartment.
La mise en place n'est pas très compliqué mais il ne faut rien oublier.
Le readme de Apartment est bien fait : https://github.com/influitive/apartment
Personnellement j'ai créé l'extension manuellement :

sudo -s -u postgres
psql
\c mabasededonnees
CREATE SCHEMA hstore; CREATE EXTENSION HSTORE SCHEMA hstore;

Ensuite il faut rajouter dans la config d'apartment :

Apartment.configure do |config|
  [...]
  config.persistent_schemas = ['hstore']
  [...]
end

Egalement dans le database.yml :

development:
  adapter: postgresql
  host: localhost
  database: mabasededonnees
  username: sylvain
  password: sylvain
  schema_search_path: "public,hstore"

La difficulté, ici c'est qui si vous faites un rake apartment:migrate ou rake db:migrate vous allez avoir une erreur :
PG::UndefinedObject: ERROR:  type "hstore" does not exist
Parce que l'extension n'a pas pour propriétaire "sylvain". Il faut donc retourner sur psql pour corriger le tir :

sudo -s -u postgres
psql
\c mabasededonnees
ALTER SCHEMA hstore OWNER TO "sylvain";

Le  "rake apartment:migrate" devrait mieux se passer maintenant.

vendredi 17 janvier 2014

Chainer ses méthodes sans redouter un "NoMethodError" ou "undefined method for NilClass" avec try

Il peut être pratique de faire un :

@voiture.roues.first.gonflage

Voiture étant un objet de la classe Voiture.

Roue est une classe et elle belongs_to Voiture

gonflage est un attribut de roue.

Ici pour arriver jusqu'à gonflage, on peut rencontrer plusieurs nil :

@voiture peut être nil. 

Si @voiture n'est pas nil, alors roues.first peut renvoyer nil.

Eh bien il existe un fonction try sur Object (méthode qui vient de Rails et non du Ruby pur) qui permet d'essayer d'appeler une méthode, sur la classe ou sur nil, de sorte que :

@voiture.try(:roues).try(:first).try(:gonflage) renverra soit la valeur de gonflage soit nil.

mercredi 11 septembre 2013

Faire fonctionner l'API JSON de Devise 3.1.0 avec Rails 4

Lors de la migration d'une de mes applications rails 3 en rails 4 (et devise 2.0.1 en 3.1.0). J'ai eu des petits soucis, deux pour être précis, un lié à Devise >2.0.1 et un à Rails >3 :

1) Rails 4

Rails 4 : ne permet plus d'action si l'authenticityToken n'est pas présent ou invalide (comme c'est pour une API, je ne veux pas de Auth..Token), voici la solution :

#protect_from_forgery with: :exception
protect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json' }

Si le format de la requête est en JSON on ne protège pas l'action. A vous de voir si ça pose un problème de sécurité.

2) Devise

Il faut dire explicitement à Devise de répondre aux requêtes json : à mettre dans config/application.rb et non dans l'initalizers/devise.rb !

config.to_prepare do
   DeviseController.respond_to :html, :json
end

Cette API est par exemple utilisée par RubyCas devise authenticator.

Normalement tout devrait fonctionner.

A lire aussi :

https://github.com/plataformatec/devise/issues/2209

https://github.com/plataformatec/devise/issues/2215

lundi 8 juillet 2013

Interfacer RubyCas avec une application RubyOnRails et Devise

RubyCas gère exclusivement le Single Sign On (SSO). En aucun cas il ne gère la gestion des utilisateurs (création de compte, mot de passe oublié, compte verrouillé, etc) : pour tout ça il faut une application séparée (ou bien le faire soi même sur l'application sinatra rubyCas). Devise est un gem reconnu qui fait tout ça très bien, pas question de réinventer la roue !

Le problème c'est que de base les authenticators (module de rubyCas de connexion aux données) ne permettent pas de se connecter à une application avec Devise. Vous pouvez par exemple vous connecter en direct à la base de donnée pour hasher le mot de passe avec BCrypt et vérifier que le hash corresponde (Module SQLBcrypt, SQL, SQLEncrypted). Certe ça fonctionne mais vous perdez l'intérêt de Devise (verrouillage de compte, compte non confirmé, etc).

Un développeur a codé un authenticator pour Devise (via l'api REST Json), sa pull-request est en attente sur Github mais comme j'en ai besoin je l'ai testé et ça marche. Ça marche bien ! Voici le lien vers le fichier : https://github.com/atyndall/rubycas-server/blob/054f219e0dd544392c913597c1f0275ac7c85af2/lib/casserver/authenticators/remote_devise.rb

Par contre il y a un bug pour devise >= 2.2.0 donc utilisez la dernière en 2.1. Et n'oubliez pas de lire mon commentaire en bas de la pull-request concernant include_root_in_json (ça vous évitera de chercher quelques heures).

Lien vers la pull-request : https://github.com/rubycas/rubycas-server/pull/155

vendredi 5 juillet 2013

Single Sign On (authentification centralisée) avec RubyCas

RubyCas-Server est une application sinatra qui respecte la norme CAS (central authentification service). Elle permet le single sign on. (Wiki RubyCas : https://github.com/rubycas/rubycas-server/wiki)

RubyCas-server retient le service qui demande l'authentification mais si l'on effectue quelques manipulations (création de compte par exemple), le redirection vers le service ne sera pas effective. Il n'y a pas grand chose à faire pour palier à ce problème. Il suffit d'activer les sessions dans rubycas-server. Comme il s'agit d'une application sinatra il faut activer les sessions manuellement :

dans le fichier lib/casserver/server.rb

enable :sessions

Ensuite ligne 307 (dans la route get "#{uri_path}/login" do) il faut retenir le service et le surcharger en cas d'autres redirections, remplacer la ligne @service = clean_service_url(params['service']) par

if params['service'].nil? or params['service'].empty? then
@service = clean_service_url(session['service'])
else
session['service'] = params['service']
@service = clean_service_url(params['service'])
end

Maintenant vous aurez la redirection vers le service effective même après une création de compte, un mot de passe oublié ou autre !

vendredi 24 mai 2013

ActionMailer : envoyer un email avec une adresse par défaut ou personnalisée

Il peut arriver qu'on veuille envoyer un email avec une adresse par défaut ou personnalisée.

Pour cela, vous pouvez utiliser VotreMailer.default_params[:from] pour éviter de copier/coller l'adresse email, exemple :

class Notifier < ActionMailer::Base
  default :from => "webmaster@example.com"
  def notification(email)
    from = Notifier.default_params[:from]
    if not email.blank? then
      from = email
    end
    mail(:from      => from,
         :to        => to,
         :subject   => 'Notification de téléchargement de fichier') do |format|
      format.html { render }
      format.text { render }
  end
end

C'était l'astuce du jour...

- page 2 de 14 -