Rails newbie - how to structure a calendar generating app - ruby-on-rails

I'm working on a service to provide our students and faculty with one single calendar (ICS subscription) of their academic dates (start and end of term & exam periods, class dates and times, exam dates and times, etc). I'm a Ruby and Rails newbie; we're starting to work more with it here so I figured this would be a good learning opportunity. I'm having trouble figuring out how to structure and model (if at all) certain parts of the app.
The app is conceptually pretty basic:
User logs in and a user record is created for them. A UUID is generated and stored on the user's record; it's used to generate their ICS URL (http://myservice.foo/feeds/johndoe_ce4970706f320130588b109add5c7cb0.ics).
When the user requests their ICS file (through the above URL), I need to query a bunch of different systems in order to get information in order to build a calendar:
The Student Information System (SIS) contains the user's schedule (e.g. johndoe is taking ENGL 100 on MWF from 10:30 - 11:20). I need to parse this data and create events.
Our online learning management system, Canvas, provides a calendar of assignments for courses contained inside it. It's accessible as an ICS file, so I need to pull down that file, parse it and include it in the "master" calendar that my app will generate.
Instructors can specify an additional ICS URL for their course so that they can include arbitrary events not provided by either of the two above sources. Like the Canvas calendar, I need to download and parse that ICS.
I have the first part working; I can log in through our single sign-on system (CAS) and a user record is created with a generated UUID. I'm not sure how to handle the second part, though. I don't need to store much permanent data; basically, I only need to keep around the user record (which contains their username, the generated UUID, and some access tokens for the Canvas LMS). The feed will be generated the first time it's requested, cached for some period (and regenerated on-demand when needed).
Where should I be putting the parsing and generating code? I'd like it to be somewhat modular as I expect that we'd be adding other data sources as they crop up. Should I be creating calendar and event models if I'm not actually persisting that data?

No, there is no need to create an empty model for interaction with 3rd party services. I had a similar problem, where I needed to receive data from an external service and wanted it to be modular. One of recommended solutions I found was to create a class (that handles business logic of the interaction with the external service) in the "lib" folder under the root directory of your rails project.
It later can be required in your controller and used to receive date from the third party service. Or if you want it autoloaded, then you can add path to lib directory in your application.rb file under config.autoload_paths setting.

Related

Logging data changes for synchronization

I am looking for solution of logging data changes for public API.
There is a need to tell client app which tables form db has changed and need to be synchronised since the app synchronised last time and also need to be for specific brand and country.
Current Solution:
Version table with class_names of models which is touched from every model on create, delete, touch and save action.
When we are touching version for specific model we also look at the reflected associations and touch them too.
Version model is scoped to brand and country
REST API is responding to a request that includes last_sync_at:timestamp, brand and country
Rails look at Version with given attributes and return class_names of models which were changed since lans_sync_at timestamp.
This solution works but the problem is performance and is also hard to maintenance.
UPDATE 1:
Maybe the simple question is.
What is the best practice how to find out and tell frontend apps when and what needs to be synchronized. In terms of whole concept.
Conditions:
Front end apps needs to download only their own content changes not whole dataset.
Does not invoked synchronization when application from different country or brand needs to be synchronized.
Thank you.
I think that the best solution would be to use redis (or some other key-value store) and save your information there. Writing to redis is much faster than any sql db. You can write some service class that would save the data like:
RegisterTableUpdate.set(table_name, country_id, brand_id, timestamp)
Such call would save given timestamp under key that could look like i.e. table-update-1-1-users, where first number is country id, second number is brand id, followed by table name (or you could use country and brand names if needed). If you would like to find out which tables have changed you would just need to find redis keys with query "table-update-1-1-*", iterate through them and check which are newer than timestamp sent through api.
It is worth to rmember that redis is not as reliable as sql databases. Its reliability depends on configuration so you might want to read redis guidelines and decide if you would like to go for it.
You can take advantage of the fact that ActiveModel automatically logs every time it updates a table row (the 'Updated at' column)
When checking what needs to be updated, select the objects you are interested in and compare their 'Updated at' with the timestamp from the client app
The advantage of this approach is that you don't need to keep an additional table that lists all the updates on models, which should speed things up for the API users and be easier to maintain.
The disadvantage is that you cannot see the changes in data over time, you only know that a change occurred and you can access the latest version. If you need to track changes in data over time efficiently, than I'm afraid you'll have to rework things from the top.
(read last part - this is what you are interested in)
I would recommend that you use the decorator design pattern for changing the client queries. So the client sends a query of what he wants and the server decides what to give him based on the client's last update.
so:
the client sends a query that includes the time it last synched
the server sees the query and takes into account the client's nature (device-country)
the server decorates (changes accordingly) the query to request from the DB only the relevant data, and if that is not possible:
after the data are returned from the database manager they are trimmed to be relevant to where they are going
returns to the client all the new stuff that the client cares about.
I assume that you have a time entered field on your DB entries.
In that case the "decoration" of the query (abstractly) would be just to add something like a "WHERE" clause in your query and state you want data entered after the last update.
Finally, if you want that to be done for many devices/locales/whatever implement a decorator for the query and the result of the query and serve them to your clients as they should be served. (Keep in mind that in contrast with a subclassing approach you will only have to implement one decorator for each device/locale/whatever - not for all combinations!
Hope this helped!

Simperium multiple users accessing data

In the Simperium documentation/help section there is the following text:
All the data that is created seems like it must be tied to a user - is
that correct? Is it possible to have data that isn't tied to a user -
say a database of locations or beers?
Yes, though this isn't very clear yet. You can create a public user
(i.e., a public namespace) with an access token you share with other
users of your app so anyone can read/write to that namespace.
It's possible to limit this to read-only access as well if you need to
authoritatively publish data from a backend service.
Is there an actual example with this?
The scenario I have is as follows
My app will have a calendar
The primary user can add and remove data from the calendar
They will want to invite other users to add and remove data, my thought is that they can give them a token, the user can use their email address and this token to sign in
Am I on the right track?
You're definitely on the right track, but a little too far ahead on that track. The scenario you described is a great fit for Simperium, but sharing and collaboration features aren't yet released.
The help text you quoted is for authoritatively pushing content, for example from a custom backend to all users of your app. An example of this would be a news stream that updates on all clients as new content is added.
This is quite different than sharing calendar data among a group of users who have different access permissions, which is actually a better use of Simperium's strengths. We have a solution for this that we've tested internally, but we're using what we've learned to build a better version of it that will be more scalable for production use.
There's no timeline for this yet, but you'll see it announced on your dashboard at simperium.com.

Using mixpanel to build custom analytics dashboard for users

I love graphs.
I'd love to get my hands on some data and make it look pretty. But alas, I'm a little lost on what would be considered best practice.
I've selected mixpanel (only as an example) as I seems wonderfully easy to track custom events, and doesn't have any subdomain limitation like Google Analytics.
Say I had 100-1000+ users who have an account (which is publicly facing), and I'm currently tracking the public interactions their pages get. With mixpanel, I can see the data which is lovely, and I've segmented it to individual accounts. So far, so good!
But then, I want to show my users this information. And here my head begins to hurt. Do I schedule a cron jobs, pulling in the data from mixpanel and writing it to their respective accounts? Or is there a better way? I've looked into mixpanel's api (I'm using Ruby), but they keep telling me I should use the javascript api. But in using JS, how does one prevent others getting the data (ie. what's stopping someone faking mixpanel api-posts in the console, or viewing my private key?).
What would you consider a practical solution in such a case?
You can achieve this by storing the user specific events of each user with a $bucket property attached which has a value unique to each user as explained in the mixpanel docs here Mixpanel docs. If you want to still use ruby to serve the events, have a look at Mixpanel's recommended ruby client libraries
mixpanel_client looks like the much maintained option of the 2 mentioned. If you go with that then you can serve user specific events as shown in the example below(which is also in the gem's readme):
data = client.request do
# Available options
resource 'events/properties'
event '["test-event"]'
name 'hello'
values '["uno", "dos"]'
timezone '-8'
type 'general'
unit 'hour'
interval 24
limit 5
bucket 'contents'
from_date '2011-08-11'
to_date '2011-08-12'
on 'properties["product_id"]'
where '1 in properties["product_id"]'
buckets '5'
end
You could try a service like Keen IO that will allow you to generate encrypted scoped write and read API keys. Keen IO is built for customizable and programmatic analytics features such as exposing analytics to your customers, where as MixPanel is more for exploring your data in their UI. The idea with an encrypted scoped key is they will never be able to access your account, only the data you want them to see. You could easily tag your events with a customer ID and then use the Scoped Keys to ensure that you only ever show customers their own data.
https://keen.io/docs/security/#scoped-key
Also, Keen IO has an "importer" which allows you to export your mixpanel events into your Keen IO database.

How many ways to share data among activities in monodroid?

I need to share some sensitive data among activities.
I have two EditText which are basically username and password
I am consuming a webservice which on the base of provided username and password return some user info (DataType:String). Like userid,useremail etc.. which is basically in CSV format
I need these piece of information throughout my application.But i can't figure out which is the better way.
-- One way i could found out so far is to use sqlite with MonoAndroid
-- Other way i found out is using Application class
I just started to learn android today , but i want to know if there are some other ways to share data ?
As you mentioned, a global Application class and the database are two good ways to share application-wide data. One thing to be careful with is that your Application class could be recycled when the app is in the background, so you would lose any data that hasn't been persisted to something more permanent.
In addition to the database, you can also persist data down to the filesystem as well. This recipe from Xamarin has an example of writing directly to a file. Most of the classes you'll need to do file access are found in the System.IO namespace. Mono for Android also supports isolated storage, which provides a higher level API for reading and writing files.
If you simply need to pass data directly between activities, you can do so by adding it as an extra to the intent. This recipe explains how to do that.
If you want to wrap up access to a particular resource in a more managed fashion that can be accessed by either other parts of your application or even external applications, you can look into implementing a content provider. Android itself provides several built-in content providers for resources like contacts and media, if you need an example of what it's like to use one. This recipe explains how to read from the contacts provider.

App for signing PDF's and categorizing them on a webserver

I've been researching the best way to implement an application for my brother's business, and have been pretty stumped in terms of how to structure my application. The application will be run on iPad 2's deployed in the field, sometimes without readily available network access (due to spotty cell coverage in the area).
Here is the abstract on what it needs to do:
1) Load a template PDF file (its a contract to sign up for what is basically cable service) that has editable fields, such as:
a) Name b) Street address c) Dates
2) be able to collect a drawn signature (very similar to any credit card app, such as Square, etc), which is then overlaid onto the PDF.
3) Save the PDF, containing drawn signature and other edited fields, as a new file. Then, upload it to a backend server, using the name of the individual and date/time as meta data for sorting into specific folders.
Without this third aspect, an employee would have to spend 30 minutes to 2 hours a day categorizing all of the app submissions, so step number 3 is a pretty important aspect to the development, even though most of the work is outside the realm of objective C. Still, i need to send the PDF file off with as much information attached to it as I can...
I'd appreciate any guidance related to the best course of action in developing this. Are there any open source applications that you guys know of that I can reference to? I have searched Apple's Developer member center and Google to no avail.
How could i implement iText properly here? Is that even the best option?? It does digital signatures as opposed to those drawn with UI Kit...
Sounds like you should have a web service with a database for storing the meta information and the path to the generated PDF with the signature and other entries.
Your app would essentially generate the PDF, make a web service call and insert information such as the client's name, date/time, whatever else you want, and then the name or path of the PDF file. The PDF file would subsequently be uploaded to a designated location with a unique file name to prevent overwriting another PDF. You could formulate the name of the file off of the corresponding Key/Id of the record in the database or you could use a GUID as the filename and for good measure concatenate the EPOCH timestamp when the file was generated. Both approaches should guarantee filename uniqueness. Another possible file name scheme Device UUID+epoch timestamp, many options available.
If you have to actually edit the PDFs, it sounds like a pretty hard requirement. Another approach would be to show the user what they need to see (ie what they have to sign) and then generate the PDF with the signature and fields populated. Since you want to upload it anyway you would probably save yourself headaches if you offload this from the iPad and do it using a remote server (as Chris suggested) generating the PDF as you need it. I've been involved in helping out an iPad app development doing property inspections - it used Docmosis to do the document generation in preview and then in submitted forms. Hope that helps even though it's a few months down the track.

Resources