Code Monkey home page Code Monkey logo

socialize-base-model's Introduction

Base Model

This package provides an extensible, yet opinionated, base from which to build your models. It uses simpl-schema for data integrity, allow/deny for simple security, and collection-hooks for actions that need to be completed before or after CRUD operations complete. The Socialize package set is built upon this package.

This is a Meteor package with part of it's code published as a companion NPM package made to work with React Native. This allows your Meteor and React Native projects that use this package to share code between them to give you a competitive advantage when bringing your mobile and web application to market.

Supporting the Project

In the spirit of keeping this and all of the packages in the Socialize set alive, I ask that if you find this package useful, please donate to it's development.

Litecoin

Patreon / Paypal

Meteor Installation

$ meteor install socialize:base-model
$ meteor npm install --save simpl-schema

React Native Installation

$ npm install --save @socialize/base-model react-native-meteor-collection2

Note

When using with React Native, you'll need to connect to a server which hosts the server side Meteor code for your app using Meteor.connect as per the @socialize/react-native-meteor documentation.

Meteor.connect('ws://192.168.X.X:3000/websocket');

Basic Usage

For save/update/delete you will need a collection attached to the Class which has a SimpleSchema attached to it. This is to ensure that you think about securing your models. Properly secured models can execute database operations completely client side without the need to manually define Meteor Methods. If you aren't familiar with Simple Schema, you can find the documentation Here.

Lets get started with a quick example by Modeling a Book.

Depending on which platform you are on, you'll need to import things, and instantiate your Collections slightly different.

// For meteor
import { BaseModel } from 'meteor/socialize:base-model';
import { Mongo } from 'meteor/mongo';
// For React Native
import BaseModel from '@socialize/base-model';
import Collection from 'react-native-meteor-collection2';
// Both Meteor and React Native
import SimpleSchema from 'simpl-schema';

//We assume that another model of an Author exists so we can import its collection here..
import { AuthorsCollection }  from "/models/Author";

//In Meteor Collection is scoped to Mongo
const BooksCollection = new Mongo.Collection("books");

//In React Native Collection is imported from react-native-meteor-collection2
const BooksCollection = new Collection("books");

const BooksSchema = new SimpleSchema({
    "userId":{
        type: String,
        regEx: SimpleSchema.RegEx.Id,
        autoValue: function() {
            if(this.isInsert){
                return this.userId;
            }
        }
    },
    "title":{
        type: String
        max: 30,
    },
    "subTitle":{
        type: String,
        max: 100
    },
    "authorId":{
        type: String,
        regEx: SimpleSchema.RegEx.Id
    }
});

class BookModel extends BaseModel {
    owner() {
        return Meteor.users.findOne(this.userId);
    }

    fullTitle() {
        return `${this.title}: ${this.subTitle}`;
    }

    author() {
        return AuthorsCollection.findOne(this.authorId);
    }
}

//Attach the schema to the collection
BooksCollection.attachSchema(BooksSchema);

//Attach the collection to the model so we can save/update/delete
BookModel.attachCollection(BooksCollection);

// This is Meteor server code and should not be added on React Native
BooksCollection.allow({
    insert(userId, book) {
        /*
        book is an instance of the Book class thanks to collection
        transforms. This enables us to call it's methods to check
        if the user owns it and the author record exists
        */
        return book.checkOwnership() && !!book.author();
    },
    update(userId, book) {
        /*
        book is an instance of the Book class thanks to collection
        transforms. This enables us to call it's methods to check
        if the user owns it and the author record exists
        */
        return book.checkOwnership() && !!book.author();
    },
    remove(userId, book) {
        /*
        book is an instance of the Book class thanks to collection
        transforms. This enables us to call it's methods to check
        if the user owns it and the author record exists
        */
        return book.checkOwnership()
    }
});

Let's examine what we have done here.

  1. Import all the necessary parts. Mongo, SimpleSchema, and BaseModel.
  2. Instantiate a Mongo.Collection and a SimpleSchema and define the schema for the model
  3. Attach the schema to the collection as our first layer of write security.
  4. Define a Book class that extends BaseModel making sure to call super(document)
  5. Attach the collection to the Book class enabling instances of the class to execute save/update/remove operations
  6. Specify allow rules for the collection as a final layer of security thus allowing total client side manipulation.

Now we are all set up to use the new Book class, and since we've properly secured our database writes through a combination of SimpleSchema and allow rules, we can now do all of our database operations using client side database methods.

Don't believe client side only database is possible? Check the results of Discover Meteor's allow/deny security challenge and take note that it mentions issues with other submissions, but you'll only find Kelly Copley listed under people who got it right. Guess how I secured my solution ;-).

With this in mind, lets insert a book in to the database client side.

//first we get get an Author for the book we want to insert
var author = Meteor.authors.findOne({firstName:"Dave", lastName:"Pilkey"});

var book = new Book({
    title: "Captain Underpants",
    subTitle: "and The Sensational Saga of Sir-Stinks-A-Lot",
    authorId: author._id,
    garbageKey: "Stripped By SimpleSchema.clean() when calling save()"
});

book.save(); //This will also clean the data before inserting so no garbage data gets through.

We do this with code (dev tools? :-P ), but you could use a form and template events, OR you could define necessary information on your SimpleSchema and use aldeed:autoform or vazco:uniforms to render a form to input this information.

Now that we have data in the database we can read it out, display it, and use the methods defined on the class as helpers. Assuming we have a template with a helper that returns a cursor from Meteor.books, we can iterate over the cursor and the context will be an instance of the Book class and we can call the methods of the class such as fullTitle, and author. Awesomely, since we've also returned a instance of the Author class from the author method, we can also call it's methods as well such as author.fullName which could concatenate the authors first and last name and return a single string.

<h1>Book List</h1>
{{#each books}}
    <p>Author's Name: {{author.fullName}}<p>
    <p>{{fullTitle}}</p>
{{/each}}

This would yield HTML like so..

<h1>Book List</h1>
<p>Author's Name: Dave Pilkey<p>
<p>Captain Underpants: and The Sensational Saga of Sir-Stinks-A-Lot </p>

Caveats

There could be some things that I guess might not be so obvious. I'll try to list them here as they come up.

  1. You must publish data for related models.. If book.author() returns a model of author that doesn't have data published for it, then it will return undefined. This is just how Meteor works.

For a more in depth explanation of how to use this package see API.md

socialize-base-model's People

Contributors

copleykj avatar storytellercz avatar dapathy avatar fabs avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.