Ruby est l’un des langages les plus utilisés sur le Web. Nous avons commencé ici une nouvelle session sur Nettuts + qui vous présentera Ruby, ainsi que les formidables cadres et outils associés au développement de Ruby. Aujourd'hui, nous allons examiner les gemmes DataMapper pour être opérationnel avec une base de données en Ruby.
DataMapper est un ORM: un mappage objet-relationnel. En gros, c'est une bibliothèque qui vous permet de travailler avec votre base de données à partir de code orienté objet. Il n'y a absolument aucun SQL dans ce tutoriel. Cependant, un ORM utilise une base de données régulière sous les couvertures; Nous allons utiliser sqlite3 aujourd'hui, mais vous pouvez simplement utiliser un autre adaptateur pour travailler avec une base de données mysql, postgresql ou autre..
Dans Singing with Sinatra - The Recall App, Dan Harper vous a présenté DataMapper. Dans ce tutoriel, nous allons approfondir notre travail avec la bibliothèque..
La première étape consiste à installer les gemmes requis. La fonctionnalité DataMapper est divisée en plusieurs gemmes différentes, vous devrez donc installer plusieurs composants différents. Bien sûr, nous ne travaillerons pas avec tout cela. mais ce sont les gemmes que vous devrez installer.
dm-postgres-adapter
, dm-mysql-adapter
, ou comme bon vous semble.Une fois que vous avez installé toutes ces pierres précieuses (voir le dernier chapitre pour savoir comment installer des pierres précieuses), nous sommes prêts à commencer..
Commençons par créer un modèle de base. Les modèles sont définis dans des classes. Cependant, nous devons d'abord nous connecter à notre base de données.
En fait, la première chose à faire est d’exiger que nos bibliothèques figurent en haut de notre fichier..
nécessite 'dm-core' nécessite 'dm-timestamps' nécessite 'dm-validations' nécessite 'dm-migration'
Alors maintenant que nous avons DataMapper dans l'environnement, connectons-nous à la base de données.
DataMapper.setup: default, "sqlite: // # Dir.pwd /database.db"
Le premier paramètre indique à DataMapper d'utiliser l'adaptateur par défaut pour le type de base de données. Le second est le lien / URL de la base de données. Comme nous utilisons sqlite, nous ne faisons que créer un lien vers un fichier de base de données. Notez qu'il n'est pas nécessaire de créer ce fichier. DataMapper va le créer pour nous.
Nous sommes maintenant prêts à créer le modèle. Comme vous le savez, ceci est une classe.
class User include DataMapper :: Resource ressource: id, Propriété série: nom d'utilisateur, Propriété String: email, Fin de chaîne
La première étape consiste à inclure le DataMapper :: Resource
module. Cela vous donne les méthodes personnalisées que vous utiliserez dans votre classe. La méthode la plus importante ici est propriété
. Ici, nous l'utilisons pour créer trois propriétés différentes: un identifiant, un nom d'utilisateur et un email. Comme vous le voyez, le premier paramètre de propriété
est un symbole qui est le nom de la propriété. La seconde est le type. Vous comprenez String, bien sûr, mais ce qui est en série. Réellement, propriété: id, série
est le raccourci de DataMapper pour la clé primaire; "série" est un entier auto-incrémenté. C'est ta clé principale!
Maintenant que nous avons créé notre modèle, nous devons migrer la base de données. Si vous ne maîtrisez pas la migration d'une base de données, vous devez modifier le schéma de la base de données. Cela peut être l'ajout d'une colonne, le changement de nom d'une colonne ou la modification des propriétés d'une colonne. DataMapper propose deux méthodes pour cela:
DataMapper.auto_migrate! DataMapper.auto_upgrade!
La différence ici est que auto_migrate!
effacera toutes les données de la base de données; la auto_upgrade!
method tente de réconcilier le contenu de la base de données avec les modifications que vous souhaitez apporter. Cela fonctionne comme suit: après votre classe de modèle, vous appelez l'une de ces méthodes. Tu ne veux pas courir auto_migrate!
chaque fois que vous chargez le modèle, bien sûr, mais vous voudrez peut-être exécuter auto_upgrade!
sur chaque recharge en développement. Je l'ai fait de cette façon dans Sinatra:
configure: développement do DataMapper.auto_upgrade! fin
Vous remarquerez que jusqu'à présent, nous n'avons pas eu à toucher une seule requête SQL; c'est l'intérêt d'utiliser ORM, c'est que vous pouvez écrire du code normal et le faire fonctionner avec des bases de données relationnelles.
Maintenant que nous avons les pieds mouillés avec DataMapper, prenons notre modèle à un autre niveau. Commençons par les horodatages.
Nous exigeons la dm-timestamps
joyau, alors pourquoi ne pas l'utiliser? Si nous ajoutons les propriétés 'created_at' et 'updated_at' au modèle, cette gem mettra automatiquement à jour ces champs.
propriété: created_at, DateTime propriété: updated_at, DateTime
Bien sûr, vous n'avez pas besoin d'ajouter les deux, si vous ne les voulez pas.
Vous pouvez ajouter plusieurs options à chaque champ. Par exemple, si vous souhaitez qu'un champ soit obligatoire, unique ou qu'il ait une valeur par défaut, vous pouvez le faire ici. Créons un modèle de publication pour présenter certaines de ces choses:
class Post include DataMapper :: Propriété de la ressource: slug, String, clé: true, unique_index: true, valeur par défaut: lambda | resource, prop | resource.title.downcase.gsub propriété "", "-": titre, Chaîne, obligatoire: true propriété: corps, Texte, obligatoire: true propriété: created_at, dateTime propriété: updated_at, dateTime end
Nous mélangeons un peu les choses ici; nos 'titre' et 'corps' sont des champs obligatoires. Nous définissons la propriété 'slug' comme la clé primaire et disons qu'il doit s'agir d'un index unique. Ne soyez pas effrayé par la valeur par défaut de «slug». Bien sûr, vous pouvez simplement utiliser une valeur brute, quel que soit le type de votre propriété, mais nous faisons quelque chose de plus. Ruby (et d’autres langues) a des lambdas, que vous pourriez considérer comme une petite fonction. C'est quelque chose qui peut prendre? Paramètres? et renvoyer une valeur, tout comme une fonction. Si nous utilisons un lambda comme valeur de la propriété 'default', DataMapper lui transmettra la ressource (ou l'enregistrement de base de données avec lequel vous travaillez) et la propriété elle-même (dans ce cas, 'slug'). Alors ici, ce que nous faisons prend la valeur dans resource.title
(la propriété title), en le mettant en minuscule et en utilisant gsub
méthode (pense global sousla constitution) pour basculer chaque espace en tiret. De cette façon, quelque chose comme ça:
"Ceci est un titre"
Deviendra ceci:
"c'est-un-titre"
Remarque: Ne vous méprenez pas sur la façon dont nous utilisons les options ici. Tout d'abord, rappelez-vous que lorsqu'un hachage est le dernier paramètre d'une méthode, il n'est pas nécessaire d'ajouter les accolades. En outre, avec Ruby 1.9, il existe une nouvelle syntaxe de hachage. Auparavant, les hashes ressemblaient à ceci:
: clé => "valeur"
Vous pouvez toujours le faire dans la version 1.9 et vous devez le faire si vous n'utilisez pas de symboles comme clés. Mais si vous utilisez des symboles comme clés, vous pouvez le faire à la place:
valeur clé"
En gros, il suffit de déplacer les deux points à la fin du symbole (pas d’espace!) Et de retirer la fusée..
Vous pouvez faire beaucoup de choses avec la validation dans DataMapper, et vous pouvez tout lire à ce sujet ici. Cependant, regardons les bases.
Il y a deux façons de faire des validations; nous allons utiliser la méthode qui ajoute vos validations au hachage des options. Pour la propriété email dans le modèle User, nous allons définir la validation du format:
propriété: email, String, format:: email_address
Dans ce cas, nous utilisons une expression rationnelle intégrée proposée par DataMapper; nous pourrions y mettre une regex personnalisée si nous voulions autre chose.
Exigeons une certaine longueur sur le mot de passe:
propriété: mot de passe, String, longueur: 10? 255
Si vous n'êtes pas familier avec le 10? La notation 255, c'est une gamme Ruby. Nous disons que le mot de passe doit comporter entre 10 et 255 caractères..
Qu'en est-il des clés étrangères? DataMapper rend cela très facile. Associons nos modèles User et Post. Nous voulons qu'un utilisateur puisse avoir plusieurs messages et qu'un message appartienne à un utilisateur..
Dans le modèle utilisateur, ajoutez cette ligne
a n,: messages
Ensuite, dans le modèle Post, procédez comme suit:
appartient_à: utilisateur
Dans la base de données, cela ajoute un identifiant d'utilisateur
propriété à une table de poste. En pratique, c'est vraiment facile. on verra ça bientôt.
Si vous souhaitez personnaliser l'entrée pour une propriété donnée, vous pouvez ajouter des accesseurs de propriété personnalisés. Par exemple, supposons que nous voulions nous assurer que le nom d'utilisateur d'un utilisateur est toujours stocké en minuscule. Nous pouvons ajouter des méthodes d'accès aux propriétés similaires à celles d'une classe normale. De cette façon, nous prenons la valeur que l'utilisateur tente de stocker et la réparons. Faisons cela:
def username = nouveau_nom_utilisateur super nouveau_nom_utilisateur.downcase end
Nous définissons le nom d'utilisateur =
, Ainsi, lorsque le nom d'utilisateur est attribué, il sera mis en minuscule. le super
une partie passe juste notre valeur à la super méthode de cette méthode, qui est celle que nous avons surchargée.
Note: Selon la documentation (voir ici et ici), nous devrions pouvoir faire @nom_utilisateur = nouveau_nom_utilisateur.downcase
dans la méthode ci-dessus. C'est ce que j'ai fait dans le screencast et, comme vous le savez, cela n'a pas fonctionné comme prévu. Depuis l’enregistrement du screencast, j’ai découvert que la documentation était fausse et que super
est le moyen de le faire.
Eh bien, maintenant que nos modèles sont créés, ajoutons quelques enregistrements pour les tester. Nous pouvons le faire de plusieurs manières. Tout d'abord, nous pouvons créer un enregistrement avec le Nouveau
méthode, en passant un hachage d'attributs ou en les assignant individuellement.
user = User.new nom d'utilisateur: "JoeSchmo", prénom: "Joe", nom de famille: "Schmo", email: "[email protected]", mot de passe: "password_12345" user.save user = User.new user.username = "Andrew" # etc. user.save
Lors de l'utilisation Utilisateur # nouveau
, vous devez appeler le enregistrer
méthode pour mettre réellement l'enregistrement dans la base de données. S'il y a une erreur (rappelez-vous ces validations?), Le enregistrer
La méthode retournera false. Ensuite, vous pouvez aller au les erreurs
propriété pour voir les erreurs; c’est un objet DataMapper :: Validations :: ValidationsErrors, mais vous pouvez effectuer une itération sur les erreurs avec chaque
méthode.
user.errors.each do | error | met fin d'erreur
Si vous voulez créer et sauvegarder un enregistrement d’un coup, utilisez la commande créer
méthode, bien sûr en passant un hachage d'attributs.
User.create nom d'utilisateur: "joeschmo", prénom: "Joe", nom de famille: "Schmo", email: "[email protected]", mot de passe: "password _! @ # $%"
Boom: créé et enregistré!
Que diriez-vous de trouver un enregistrement dans la base de données? Si vous connaissez la clé de l'enregistrement que vous recherchez, utilisez simplement la méthode get:
Utilisateur.get (1) Post.get ("this-is-a-title")
Oui, vous constatez que cela fonctionne avec les clés entières normales et les autres types de clés. Depuis que nous avons dit que la limace était la clé dans la Poster
modèle, nous pouvons obtenir
en limace.
Qu'en est-il des champs qui pourraient être les mêmes pour plusieurs enregistrements? Vous avez trois options pour cela: le premier, le dernier et tous. Il suffit de leur donner un hachage et ils obtiennent les documents pour vous.
Nom d'utilisateur.first: "Andrew" Utilisateur.last (: nom => "Schmo") User.all #get tout le message
Vous pouvez faire beaucoup plus avec DataMapper; consultez la documentation pour plus! Frappez la boîte de questions si vous avez des questions.