Using meteor's Collection FS in Iron Router / Iron Cli - meteor

I have been scratching my head while trying to adapt a collection fs for my iron cli generated project.
Iron cli uses iron router. This is the tutorial i am following https://medium.com/#victorleungtw/how-to-upload-files-with-meteor-js-7b8e811510fa#.mdionmurk
The first snippet
var imageStore = new FS.Store.GridFS(“images”);
Images = new FS.Collection(“images”, {
stores: [imageStore]
});
and the second is the deny/allow rules
Images.deny({
insert: function(){
return false;
},
update: function(){
return false;
},
remove: function(){
return false;
},
download: function(){
return false;
}
});
Images.allow({
insert: function(){
return true;
},
update: function(){
return true;
},
remove: function(){
return true;
},
download: function(){
return true;
}
});
Where should the first snippet go specifically and where should the second snippet go?.Incase anyone is wondering the structure of an iron-cli this is how it looks like https://github.com/iron-meteor/iron-cli

Based on the generated structure, your first snippet will go into app/lib/collections and your second will go into app/server/collections.

Related

Adding collection items as routes in Meteor

I have a meteor project where all my users have their own profile page setup in this way using routes:
Routes code:
Router.route('/#:username', {
name: 'profile',
controller: 'ProfileController'
});
ProfileController = RouteController.extend({
template: 'profile',
waitOn: function() {
return Meteor.subscribe('userProfile', this.params.username);
},
data: function() {
var username = Router.current().params.username;
return Meteor.users.findOne({
username: username
});
}
});
Server code:
Meteor.publish('users', function() {
return Meteor.users.find({}, {fields: {username: 1, emails: 1, profile: 1, roles: 1}});
});
Meteor.publish('userProfile', function(username) {
// Try to find the user by username
var user = Meteor.users.findOne({
username: username
});
// If we can't find it, mark the subscription as ready and quit
if (!user) {
this.ready();
return;
}
// If the user we want to display the profile is the currently logged in user
if(this.userId === user._id) {
// Then we return the curresonding full document via a cursor
return Meteor.users.find(this.userId);
} else {
return Meteor.users.find(user._id, {
fields: {
profile: 0
}
});
}
});
I want to do something similar with a pages collection that I've set up. Creating the collection works and the collection page has an _id field that is made upon creation.
Right now the program works nicely for users where mysite.com/# works. Now I want the same thing to work for mysite.com/&
I've basically attempted to do the exact same thing as I did in the above code with the user name but it wasn't working. I've checked to make sure my creation of the collection items are working and they are. But somehow I can't figure out how to do this same thing with collections since I'm relatively new to using routes.
This is what I've attempted:
Here's my routes:
var pageRoute = '/&:_id';
Router.route(pageRoute, {
name: 'page',
controller: 'PageController'
});
PageController = RouteController.extend({
template: 'page',
waitOn: function() {
return Meteor.subscribe('Page', this.params._id);
},
data: function() {
var _id = Router.current().params._id;
return Meteor.pages.findOne({
_id: _id
});
}
});
Server code:
Meteor.publish('pages', function() {
return Pages.find({});
});
Meteor.publish('Page', function(_id) {
// Try find the page by _id
var page = Meteor.pages.findOne({
_id: _id
});
// If we can't find it, mark the subscription as ready and quit
if (!page) {
this.ready();
return;
}
// If the page we want to display is not claimed, display it
if(true) {
return Meteor.pages.find(this._id);
} else {
// Redirect to the page
}
});
The Schema of the Page Collection:
_id: ,
createdAt: ,
CreatedBy: ,
claimedAt: ,
claimedBy: ,
Update:
I've scoped it down to this problem, I get the following error in the console server-side:
I20160202-11:16:24.644(2)? Exception from sub qrPage id 2kY6RKCTuCpBDbuzm TypeError: Cannot call method 'findOne' of undefined
I20160202-11:16:24.645(2)? at [object Object].process.env.MAIL_URL [as _handler] (server/ecclesia.life_server.js:40:33)
I20160202-11:16:24.645(2)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20160202-11:16:24.645(2)? at [object Object]._.extend._runHandler (livedata_server.js:1023:17)
I20160202-11:16:24.645(2)? at [object Object]._.extend._startSubscription (livedata_server.js:842:9)
I20160202-11:16:24.646(2)? at [object Object]._.extend.protocol_handlers.sub (livedata_server.js:614:12)
I20160202-11:16:24.646(2)? at livedata_server.js:548:43
This error occurs whenever I try to direct to mysite.com/&<_id>
Based on this website: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
It looks like # is considered an unsafe character to use in a URL string. On the web page above, it looks like there are several symbols you could use instead as safe characters.
I just tried this on my own machine, and I don't think Meteor plays nicely when the # is introduced in the URL.
This got it working...
Publications:
Meteor.publish('qrpages', function() {
return QRPages.find({});
});
Meteor.publish('qrPage', function(id) {
// Try find the qrpage by _id
var qrpage = QRPages.find({_id: id});
// If we can't find it, mark the subscription as ready and quit
if (!qrpage) {
this.ready();
return;
}
return qrpage;
});
Routes:
var qrpageRoute = '/$:_id';
Router.route(qrpageRoute, {
name: 'qrpage',
controller: 'QRController'
});
QRController = RouteController.extend({
template: 'qrpage',
waitOn: function() {
var id = this.params._id;
return Meteor.subscribe('qrPage', id);
},
data: function() {
var id = this.params._id;
return QRPages.findOne({
_id: id
});
}
});

Multiple Data Contexts in router - Meteor

I'm building a meteor app and on one route I'm adding multiple data context like so -
this.route('orgPage', {
path: '/org/:title',
data: {
orgs: function () {Orgs.findOne(this.params._id)},
projects: function() {Meteor.subscribe('projects', this.params._id)}
}
The only problem is that when I try to access this data in my templates js file, I can't access the _id or any of the attributes of orgs.
I've tried several approaches, but it always returns undefined. If I use a single data context, it works perfectly. Here is the function that doesn't function properly -
Template.orgPage.events({
'click #newProject': function(e) {
$('#npModal').modal();
},
'submit #npModal form': function(e, template) {
e.preventDefault();
if(!$(e.target).find('[name=newTitle]').val()) {
var projectTitle = 'Untitled'
} else {
var projectTitle = $(e.target).find('[name=newTitle]').val()
}
var theid = this._id;
var newProject = {
title: projectTitle,
organization: theid
}
Meteor.call('project', newProject, function(error, id) {
if (error)
return alert(error.reason);
$('#npModal').modal('hide');
$('#npModal').on('hidden.bs.modal', function (e) {
Router.go('newFields', {});
})
});
});
Anyone have any ideas? Thanks!!
You have missed a return statement. function () {Orgs.findOne(this.params._id)} should be function () {return Orgs.findOne(this.params._id)}. Further more, this inside this function won't refer to what you want, so you can't use this.params. And why do you subscribe to a subscription as a data context property? Do it in the waitOn function instead.

Route loads notFound briefly first

I have a iron route that searches for a collection item based on the url param. If it finds it, it returns the item as a data context, otherwise it renders a notFound template. The code looks like this:
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
});
The problem is the notFound template gets loaded briefly prior to profile getting returned, although I thought the waitOn function would have handled that. What's the correct pattern to have the desired result using iron router? Thanks.
Is it possible that you forgot to configure the loading and dataNotFound hooks?
Router.onBeforeAction('loading');
Router.onBeforeAction('dataNotFound');
If you want to understand what is actually going on here, please look here.
I had to check for this.ready() in data. Updated code
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
if(this.ready()){
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
}
});

Meteor JS Iron Router subscribe to data

I am using Meteor 0.8 and iron-router.
I have a single route that I use to subscribe to a number of collections. What I would like to do is create a document when you arrive on the route and then subscribe to it so I can access it.
This is my route:
this.route('product_collection', {
path: '/collection/:collection',
template: 'product_collection',
layoutTemplate: 'layout-new',
waitOn: function() { return [ Meteor.subscribe('specific_product_collection', this.params.collection), Meteor.subscribe('product_types')] },
data: function () { return ProductCollections.findOne({ url: this.params.collection }) },
onBeforeAction: function(pause){
//Prevent double rendering
if (this.ready()) {
var productType = ProductTypes.findOne({url: this.params.collection })
console.log(productType)
if(productType){
var product = {
productType: productType._id
};
Session.set("productTypeId", productType._id);
Products.insert(product, function(error, id) {
if (error) {
console.error(error);
set_notification('Oops, something went wrong.', 'Please try again later.');
} else {
Session.set("productId", id);
Session.set("productName", productType.name );
//Not working
Meteor.subscribe('specific-product', id);
console.log('should be subscribed')
}
});
}
} else {
console.log('loading')
this.render('loading');
pause();
}
},
});
Ok,
I found out the ID was different on the server vs client side location. So ended up writing a meteor method call on the server.
See reference: Retrieve _id after insert in a Meteor.method call

Backbone _.each collection.model empty

I'm trying to simply return what I request in PHP to JSON.
My problem is that each Stock is not yet completed.
Indeed, it is the "render" but "this.collection.models" is not yet completed because the request is not yet finished.
What should I do to correct this problem, wait until the request is finished so that the loop is done correctly.
Thank you in advance
var Article = Backbone.Model.extend({});
var Articles = Backbone.Collection.extend({
model:Article,
url: function() {
return _BASE_URL+'/sync/getLastArticles';
},
initialize:function () {
this.fetch();
}
});
var ArticlesView = Backbone.View.extend({
template:$('#articles').html(),
initialize:function () {
this.collection = new Articles();
this.render();
},
render:function () {
console.log(this.collection);
var that = this;
_.each(this.collection.models, function (item) {
console.log(item);
}, this);
},
renderArticle:function () {
;
}
});
You render before the fetch is done. What you want to do, is to wait for the fetch to complete and then render. Now how would you get notification of when the fetch is done? You have 2 options:
The success function (Not recommended by me)
// ArticlesView
initialize: function() {
_.bindAll(this); // Don't forget to BIND
this.collection = new Articles();
this.collection.fetch({
success: this.render
});
}
Now when the fetch has been successful, render is called. This however can cause scoping problems and Backbone.js offers a much nicer alternative to callback functions: events.
Event callback (prefer this)
// ArticlesView
initialize: function() {
_.bindAll(this);
this.collection = new Articles();
this.collection.on('reset', this.render); // bind the reset event to render
this.collection.fetch();
}

Resources