user login before or after main application part? - ruby-on-rails-3

Theoretical question. Lets say I build an application for managing clients, products, bills and such. All without a user login.
Is it possible to get multi user (each one with his own clients,products,...) functionality after the main application is done?
Or should I think of the multi user in the first place? How flexible is rails at this part?
thanks in advance
dennym

What you are asking for is a pattern called Multitenant. There are different ways to do it, but none are provided by Rails natively.
You could start with this slide: http://www.slideshare.net/tardate/multitenancy-with-rails
And figure out if you want to do; partitioning based on data, Rbac, model or schema.
There are is one that offers it as a service that says that it is easy to do after you have your application: http://railskits.com/saas/
But in our experience, it was a bit outdated and missing some features that we wanted.
You can also take a look at other gems like: multitenant or act_as_tenant.
We ended up using act_as_tenant and doing it from the beginning.

Related

Ways to handle security/authorization in a multi tenant API

I'm playing around with a spare time project, mainly to try out new stuff :)
This involves designing a REST API for a system that is multi tenant. Lets say you have an "organization" that is the "top" entity, this might have an API key assigned that is used for authenticating each request. So on each request we have an organization associated.
Now when a user of the API would like to get a list of, lets say projects, only those that belong to that organization should be returned. The actual implementation, the queries to the database, is pretty straight forward. However the approach is interesting I think.
You could implement the filtering each time you query the database, but a better approach would be a general pre-query applied to all "organization" related queries, like all queries for enities that belong to an organization. It's all about avoiding the wrong entities from being returned. You could isolate the database, but if that is not possible how would you approach it?
Right now I use NancyFX and RavenDB so input for that stack would be appreciated, but general ideas and best practices, do's and don't is very welcome.
In this case you could isolate your collections by prefixing them with the organization_id. It will duplicate maybe many collections.
Use case with mongodb: http://support.mongohq.com/use-cases/multi-tenant.html

Make item "Private" in rails

App Attributes:
Rails 3.2, Mongoid, Devise, Elasticsearch
Basic Structure:
User has a Post
Post can be seen by other users
Situation:
A User wants to remove the post from being view-able by other users for a period of time.
Note
Eventually I would like to extend this capability so that its possible for said user to be able to make it only viewable to certain colleagues. This way they can collaborate on the post together.
Problem:
I can't seem to think of a good way in rails to do this. One idea I had was to create a Boolean field in the post model that would allow me to achieve some of this but the ACL's would tricky and unstable at best. So I'm reaching out to the great intelligence this should be cake for some of you.
The solution you suggest is the one that occurs to me. Place a boolean flag private on the Post model, and modify the code you use to fetch Posts to exclude ones with the flag set unless they belong to the current user, (depending on whether private posts are viewable by their owner in that particular context).
I haven't actually worked with Mongoid, but I believe this is as simple as Post.any_of({private: false}, {user_id: current_user.id})
If and when you implement the collaboration functionality you discuss, all you need to do is change that code again - fetch posts that are not private, or that belong to any one of a given set of users.

User friendly and restful (rails 3)

i am a rails programmer who is on to his 3rd project now (new of course).I am looking for an answer to a general question about Restful architecture. I am sure i am doing something that has a good established answer already.
In restful approach we expose resources but some times this approach feels a little Non user friendly. For example i can expose a product via a show method and then i have another resource called sales that i can expose via product/:id/sales show template to show all sales for a product. But i am taking the user through an extra click here. The ideal will be to show product and all its associated sales on one page itself. But that is a violation of the Restful rule.
I just wanted to ask that are these rules generally broken to make the site user friendly? Being a new comer i dont want to adopt ways that are non ideal so i thought i should ask this question.
Thanks in advance.
Adding in the sales for a particular product would not be breaking any constraints from the RESTful architecture. You have the product ID in the HTTP request so you can just also get the sales for that product. Your separation of concerns should not be affected and you don't need to store a state to get this information. Just extend the model that you return with the view.
It seems like you are more concerned with straying from the convention over configuration that Rails promotes. This extension means that your model will not correlate with only one table in your database, but that is fine. The conventions are meant to reduce the configuration work that you need to do, not restrict your functionality.

Manage conflicting roles in chef

I am relatively new to chef, so I may be missing something extremely basic. After much searching I am not finding what I need, so here goes:
In Chef, I have roles that are conflicting. I need for all servers of a certain type to have roleA, except for servers with roleB.
The best way I can think of to describe it is with an example:
syslog1, syslog2
web1, web2, web3
db1, db2
mail1, mail2
Every server within this environment(dozens) has a role called syslog_client, except syslog1 and syslog2, which need to have the role syslog_server.
The syslog-server and syslog-client roles conflict, because they configure the same pieces of software differently.
These are roles rather than recipes because they actually encompass several recipes.
I thought of doing something like this:
roles/base.rb:
name "base"
description "base configuration"
override_attributes(
)
default_attributes(
)
run_list(
"recipe[one]",
"recipe[two]",
"recipe[three]",
"role[uno]"
)
unless node[:roles].include?('syslog_server')
run_list('role[syslog_client]')
end
The problem there is that the node object does not exist at this point. I have thought about moving it into the recipe, but I could not come up with a good way to do it there either. I was able to use this in the base recipe:
unless node[:roles].include?('syslog_server')
node[:roles]+=['syslog_client']
end
This adds syslog_client to the roles attribute (or doesn't) correctly, but it never actually runs the syslog_client role.
I have considered moving syslog_client into a self-contained recipe rather than a role, and moving the role attributes to the environment. This would work, because then I can just call include_recipe "syslog::client". The problem there is that virtually all of our recipes are assigned from roles (not from other recipes), and I fear that making this change will create a one-off that will be hard to keep track of. Besides that, as I mentioned already, these are actually several recipes, so adding them as a single recipe is not ideal.
We have many different server types/roles in the environment I'm currently working in, and adding role[syslog_client] to them is feasible, but not ideal. With multiple people working on this, it seems likely that someone will forget to add the recipe to a new role.
In an ideal world, something like my first solution would be possible, because that allows us to keep our environment as consistent as possible. I am open to other options though.
So to wrap up, I think what I need is someone to tell me how to:
Make the first solution work. Add a role to a run list only if another role is not present
If I cannot have #1, I'd like opinions on the best way to achieve this using the ways I've listed or other ideas I have not thought of
Please let me know if I'm missing any details about our chef setup that will be helpful.
Disclaimer: The above example is really a very simplified version of what I'm actually trying to achieve. I'm not even working with syslog, but the company it is for is very security-conscious and would not be happy with details of their environment being posted publicly. I will be as detailed as I possibly can if I've left anything out and I need to add further info.
Extending what was said above what's the issue with creating two roles. A Client and a server
The Client role includes the base role and the client function. It will get applied to all servers through replacing references to 'base' with this role in all other roles. Meaning those roles still get base but get client as well.
The server is a stand-alone role which only applies to those servers and has the base and then the server role?
That way both client and server get the base role applied to them without duplicating the definition of what the base role is. You still manage that base role as you want but you use aggregation in the creation of roles?
When a new role is created the user won't start by adding base but instead adding the syslog_client role which gives them base as well.
To me that feels like the way Chef is pushing you with the creation of roles. What we have is 1 role that applies to all servers, some that apply to 1 subtype of servers but not anothers. That way our leaf role as in the one that gets applied actually consists of 4 or 5 other roles. What's common is modelled in a way that can be shared without the need for logic within?
The other option would be to add the client recipe to every node and the first exeuction step is to check the nodes role and if it says server just basically skip the recipe execution? Which would be the same as the logic which you were wanting to use to add the recipe but it would live in the recipe and control the execution?
unless node[:roles].include?('syslog_server')
#Do your client install
end

How to separate the responsibility in application?

For example,
I want to separate the online shop into three parts.
User: the user related information, for example, they login. logout.
Communication: sending email, or newsletter modules.
ShoppingCart: displaying order.
Ok, these three module is the main function of of my little online store.
Clearly, the user medule, deal with its own stuff, for example, user change their profile pic(ok, I think it is non-sense to have a profile pic for user, just think it is an example.)
user ---call---> user
But I got a problem here, is when the user doing some functions, which require cross-module call....
Let me give a example, if the user lost the password, the user needs to use the communication method to send a new password to him/her...The situation will become somethings like that:
user ----call---> communication
A worse situation is use all the modules, here is the situation:
The user using a shopping chart to deal with his/her shopping, after that, he /she make the order, and a invoice use communication modules to send to the user.
user ----call---> shoppingCart ---call---> Communication
Therefore, each module is not separate, all modules knows each others.... But I don't want to do that, for example, this time I am doing a new application, for example, I doing a video sharing web site which only use "user" and "communication", I don't really need the "shoppingChart. ", and having a new video module.....
It is ok for me "upgrade" my user and communication method to deal with the video module, but the question is, if I got something bugs fix, for example, the getFullName method is doing something wrong, when I need to "upgrade" back the online shop application, I need to take the "video" module too.....
What I wanna to ask is, how to separate their responsibility, and how to make the code more reusable? Thank you.
It is good practice to minimize the coupling in your application, but removing it entirely is not always possible.
My recommendation would be to build base classes User, Communication, and ShoppingCart that provide only basic interfaces, such as getFullName()
Then, for each application, write separate wrappers that are able to interact with your base classes. You may have an OnlineShopping class and a VideoSharing class, that contain the functions you need that are specific for each application.
There are a number of structural patterns that may help you out with your design. Also, take advantage of inheritance for functionality that is similar across all applications.