Organizing and grouping sophisticated processes in rails - ruby-on-rails

As an example, lets say I have 4 models: Product, Order, Customer, Store
When an order is placed by a customer in a store, the store's owner would get an email asking to confirm the UPC code on the product. Once confirmed, the customer would get an email with a code that when they enter it into their portal, it activates the product.
There is a lot of logic here, which spans several models. For example, when the order is completed, it creates a new inactive product with a confirmation key. The store owner accesses this product by its confirmation key and adds the upc information to it. Only then, once the product has upc information can the customer confirm it.
TL;DR - My question is, what is the best way to group a large process, which involves many models, into a central location? Instead of accessing several other models from within one model, it would make more sense to have it centralized. Is there a best-practice for this type of logic?

This case is typically going to result in a "Service Object" that would be placed in /lib.
This allows for testing the workflow in isolation and doesn't fatten up models unnecessarily.
You can find a good intro to Service Objects here:
https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services
http://multithreaded.stitchfix.com/blog/2015/06/02/anatomy-of-service-objects-in-rails/

Related

Is it okay to allow orders to be placed in rails web app without session data or users class

I have a question for a project I am working on. I am working on a RoR project in which a site is selling a single type of item, a book. The person I am creating this for does not want to deal with users creating user account to check out as the sales season is very short for this product, the purchases are done once per year, and the site only sells a single item.
I am wondering if there is something wrong with the implementation I am thinking of. What I was envisioning was a single database class called Orders. visitors to the site would simple fill out an order form with payment details through stripe and click submit. If they payment clears, the order with all the Orders information would be persisted to the DB. If the payment fails then it is not persisted and the relevant error information is displayed in using flash.
I suppose the meat of my question is; is there anything inherently 'wrong' about implementing this model without a users class and just having visitors to the site place orders?
I am a fairly new developer and this is my first big project so any feedback is appreciated!
If your requirements say that it is okay, then it is okay, if your requirements say it is not okay, then it is not okay.
There's not more to say, since only you know what your requirements are.

Which architure/mindset will be suitable for building a web app that users can purchase features like Azure does?

We recently had a new business rule that will require our users to pay for individual modules in our web application.
So, all the features we build in the application will not apply to all users. Some users can choose to add features that they want.
I've tried researching into an architecture/mindset to how to approach this development.
If I could get an idea on how to get started with this.. I would very much appreciate it.
I work with .NET web applications, and Microsoft SQL Server.
Thanks.
First list what "objects" or things you need to keep track of.
Users
userid
fullname
can manage his features? You said not all users can
...
Features:
featureid
description
cost
...
UserHasFeature
a link between a user and a feature
each line is userid, featureid
Using this you can query which user has what feature. Or list the users that have access to a particular feature.
In your web app, you will need administrator functions:
users management: add, remove, modify, list
feature: add, remove, modify, list
link management: add, remove, list
Reports: whatever reports you want to have
And user functions:
user: signin, modify, reset password, view all features, view features the user already has, add a new feature, remove a feature
reports: total cost of features the user is using, others
Now this is a very quick first draft. There are a lot of missing requirements:
approval workflow: can a user modify his features without the approbation of X?
payment methods
project number for internal billing
cost structure: monthly, one time, ...?
managers can view the features of the employees he manages?
...
This to remember:
Start with objects in your projet. These become tables.
Characteristics of the objects become fields in your tables.
If the same characteristic appears in many object tables, with the same values, consider creating a new table for these. Ex. in an address, you would not leave the country value as a simple VARCHAR field. You would link to another table with the country values.
List the relations. These become foreign keys, or link tables.
Split your objects. So apply 1NF, 2NF and 3NF at least. It is enough for most applications. (NF == Normal Form).
Each table and links require administrator pages (CRUD)
Users have a limited view related to their features only.
This is a huge subject, I could go on and on, but this could get you started.
Have fun!

Getting List of All Instructor Enrollments

I've been using /d2l/api/lp/1.4/enrollments/myenrollments/ to get a list of enrollments for the current user. Now, I want to just get the enrollments where the user is in an instructor role. So, I'm trying to use:
/d2l/api/lp/1.4/enrollments/users/{userId}/orgUnits/?roleId=105
When I use that, I get an empty list of Items back, with or without the roleId specified.
My expectation is that just calling it without the roleId would return the same list as /d2l/api/lp/1.4/enrollments/myenrollments/. But, I always get an empty list, except when I log in as a system administrator. Only in that case do I get anything back.
Does anyone have any suggestions on what I might be doing wrong?
The various my* API calls specifically exist to provide end users to fetch back details about the system that they should know, but segregated from information they shouldn't (that's available through the more general routes for a particular area). Enrollments is a good example of this. And end-user should be able to see their own enrollments, but they should not have generalized access to enrollment records. In particular, the D2L system treats the D2L user role belonging to an enrollment as fairly privileged information, and a side effect of this is that it's not generally visible to end users.
One way that applications and services can cope with achieving goals that the end-user cannot themselves perform is to have set up a "service account" that the app can use to make calls of an administrative nature, to fetch back data that they can use in the business logic around presenting information to end users. In this particular case, you could, for example use the service account to make calls about a user's enrollments, and then present the user with logic that could filter the list of their enrollments by "these are the student ones, and these are the ones where you're a teacher, and a tutor, and so forth".
But you'd also need to carefully consider the implications of this type of activity in balance against the intentions of the client LMS's policies and administration. Even this level of information may be giving away too much to end users, in the eyes of a client LMS administrator.
Using a service account to let an app make administrative level calls must always be done with great care around the issue of information/functional leakage to end users.

Giving a user a 'primary key' inside their data domain

I have a rails app that consists of lots of accounts.
Inside these accounts users can create tickets.
What is the best way to give each ticket a Id that is sequential inside their account?
Obviously managing the id's myself seems to be the initial answer, but this seems to be filled with all sort of edge cases that would cause issues (for instance, two tickets writing down to the DB at once...)
I think you'll end up managing them yourself - I've implemented something similar previously, account stored 'current_ticket_id' and then when a ticket (for example) get's created it is still stored with a global PK but then an observer assigns it a friendly_ticket_id and then increments to one on the account model for the next time round. You can use the friendly_ticket_id scoped to the account via your URLs to make sure you get the right ticket back.

Is this the right way to associate models in a domain with multiple users per account?

Using Rails and am new to it (and RDBMs). Have read lots of posts and articles on modeling and associations, but could really use a reality check on what I'm thinking for my particular case.
I have 3 main models: users, accounts, plans. The accounts are multi-user, with plans worked on by all users attached to the account (with varying privileges). If the account is destroyed I’ll also take down its users and plans.
Looks like the basic associations would be as follows. Is this correct?
users
belongs to - >
< - has many
accounts
has many ->
<- belongs to
plans
Is there any value in associating users with plans with “has many through”? I see that it would allow access like #user.plans and #plan.user[1], but can’t I access each via accounts, as in #user.account.plan?
Is it the case that with “has many through” the middle model simply belongs to the other two? All the examples I’ve seen show that. In my case, that would be inappropriate, since account actually owns the other two.
Is there a better way to model this (multiple users of an organization working on a set of one or more plans)?
Input is very much appreciated.
Your design is correct. The belongs_to terminology can indeed be a bit strange, but is proper. Use "has many through" if it makes your code more readable and obvious. (In other words, if the notion of a user having a plan makes sense, and is needed, go ahead and create the relationship. If it is more clear to conceive of the plan belonging to an account, then stick with user.account.plans.)
Your design should be sufficient so long as you don't need to restrict a user to a subsets of the plans belonging to an account, and so long as a user only belongs to a single account.

Resources