bottom up rails app associations - ruby-on-rails

I'm building a rails app from the bottom up and need a little guidance on the model associations.
We have clients and engage them on multiple projects.
The client has users (their employees) who work on projects and make contributions to the project with files and notes.
We also collaborate with our clients on projects (add files, notes).
Projects have contributors (users or sub contractors that may be part of another client) who make contributions (files, notes).
So model wise I want to ensure I'm capturing everything properly.  Here's what I have, but I'm not confident its all right and am open to other associations.
Client
 has_many :projects
 has_many :users
Project
 belongs_to :client
 has_and_belongs_to_many :contributors
 has_and_belongs_to_many :contributions
User
 belongs_to :client
 belongs_to :contributor
 has_many :contributions
Contributor
 has_and_belongs_to_many :projects
 has_one :user
 has_many :contributions
Contribution
 has_and_belongs_to_many :projects
 belongs_to :contributor
I think contributions will be associated with models for files and notes; projects may be associated with a "next steps" model... All as nested resources I think.
Thanks

Have you reviewed the guide on associations? Did you do any sort of paper prototype of the model domain to clarify all these associations? Those are important parts of the process that for any moderately complex problem domain will be important for getting things off on the right foot.
I would probably make the :contributor association on Contribution a has_one association rather than belongs_to but that's probably just preference. I also agree with Phobos98 that Contributor is an unnecessary distinction from User. I think Contribution is a very nicely conceived model for relating user actions to projects. Most authentication frameworks like Devise allow you to specify roles and something like cancan would allow you fine-grained control over the permissions.
As far as nested resources go, that's really something different that just relates to how your app makes its data available. It's like building a house. You put up the walls and there's people and belongings inside, but the number of windows (routes) controls who can see what. Yes, it's helpful to have these routes available but they're not required at the beginning in order to make sure the data model is in place.
Did you actually try the model you have here and see if it worked? With scaffolding, you can try things quickly, and Rails makes changing the data model trivial, so there's no reason you can't be a little more agile with this. Just try it out and figure out what works and what doesn't. Then, you'll know what needs to change.

Related

Is maintaining multiple "sites" using the same "web app" worth the added architecture and code complexity?

This may not at first seem like a code-related question. But it truly is, in the end a very high-level architecture question, which has implications for database design, and code architecture. So please give a good moment of thought before judging this as off-topic.
I imagine my situation is not unique in the industry and I would like to learn from others' experience.
I have run a topic based video education website for 8 years. Recently I've been inspired to make one or two other websites that are essentially the same thing, but with a different topic. Everything I'll need for these new sites I already have, including searching, indexing, external content hosting, backend jobs, mailers, etc.
I'm faced with the decision of do I fork the current website for each additional website, and make the 5% alterations required, and set up all of the other services, etc? Or do I try to basically cram a number of "websites" into the same app, that would basically key off of the domain name and give a different face and content (and registration, shopping cart, menus, content, etc)?
An example of this issue is Stack Overflow itself. They have many sites "branded" slightly differently. Do they maintain separate apps for each, or do they all run off of one app?
In the first case upgrades and code development will get out of sync and become a nightmare, and in the second, this will add a significant degree of complexity to, well, mostly everything.
Both seem pretty bad. Which is least bad?
ps, it's a ruby on rails app, in case by some magic, some gem exists for this kind of thing that I don't know about.
If the functionality is the same then the you only need one app. However, if you realize that at some point that the functionality of the app are diverging, then you could add another app to handle the diverging code but keep the common app to handle all the common functionality and convert to service oriented architecture.
Forking and maintaining two sets of identical code is a nightmare that should be avoided.
You're looking at multi tenancy -- the ability for multiple "tenants" to use a single application.
Modern terminology would label this as "cloud" software, although our current HTTP architecture prevents users maintaining state, preventing it from achieving that mantle.
CMS
In the terms of your app, you'd benefit from reading up about CMS systems.
Specifically, the likes of tumblr etc work with the exact pattern you want -- single application with...
admin area
front-end
customization (background image, styling etc)
users
--
For Rails, you'd be able to create a single instance of an application, with the following structure:
#config/routes.rb
scope constraints: AccountCheck do
resources :posts, path: "" #-> url.com/
end
#lib/account_check.rb
module AccountCheck
def initializer(router)
#router = router
end
def self.matches?(request)
Account.exists?(request.subdomain) && request.subdomain
end
end
--
#app/models/account.rb
class Account < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :posts
end
#app/models/user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :accounts
has_many :posts
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :account
belongs_to :user
end
The above will give you the ability to create a subdomain-centered system, which will display the posts for the current account:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
#account = Account.find_by name: request.subdomain
#posts = #account.posts
end
end
Gem
Very simple example, hopefully shows you how you'd achieve the multi-tenancy aspect.
If you wanted to take this even further, you'd want to look at data-scoping around the Account model. This cannot be done at the db-level in any other system than pgsql; for which there's a gem called apartment to manage PGSQL schemas.
This is the best I have so far. There's a good book about this pattern by #Ryan Bigg - https://leanpub.com/multi-tenancy-rails
If you have total control over the "creative direction" for all the sites, maintaining all of them under a single site would be easier.
If you plan to retain a main site, with less frequent updates to the other sites, keeping them separate will have the advantage of reduced coupling - you can safely perform customization for a single site/app without impacting others, and avoid (further) raising the overall code complexity needed to accommodate competing requirements for multiple apps under the same site.

want to give access for many organsation

We are developing a online rails application for schools, but we want to separate that all schools to each other.
Like slack website that manage many organisation from one application and organisation only access that data.
Also like trello, they also separate organisations in one application.
So what is the best approach is use for such type of application?
How we implement this in our ruby on rails application,that we separate all schools in our Database?
Okay.
Multi Tenancy
If you're coming from the world of "native" software, you'll be best reading up on multi tenancy:
(source: theenterprisearchitect.eu)
Rails apps are multi tenant by virtue of them running through a network; they run a single instance of an app, which is then accessible to anyone on that network (remember, the Internet is a huge network).
Rails provides all the functionality you mentioned above, with the added benefit of having a lot of world-leading companies using it to run (Twitter, AirBnb, Groupon etc have all famously used Rails).
You need to read up on database system design for your application, specifically...
MVC
To better understand how you'd make an application like you referenced, you need to understand the MVC (Model View Controller) programming pattern, and it's value within the world of object-orientated system design, especially pertaining to Rails:
Rails, like many other frameworks, uses MVC to build objects. These objects are defined by the programmer, but basically allow you to create the relevant data required to provide functionality to an application like you mentioned.
Specifically, each time you access a Rails app - you'll be essentially manipulating objects filled with data from the db. I'll explain any specifics in an update if you need it.
In regards your question, the way to integrate multiple organizations/entities into a single application is to set up the database schema to manage the organization as the "parent", with users and data as extra elements:
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :users
has_many :invoices
has_many :clients, through: :invoices
end
#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :company
has_many :invoices
end
#app/models/invoice.rb
class Invoice < ActiveRecord::Base
belongs_to :company
belongs_to :user
has_many :clients
end
This will give you the ability to use something like the following:
#config/routes.rb
constraints Account do
root "invoices#index" #-> http://company.url.com
resources :invoices #-> http://company.url.com/invoices/3
end
#lib/account.rb
class Account
def matches?(request)
Company.exists?(request.subdomain)
end
end
You'd then be able to use Devise to sign the user into the organization, allowing them to add / edit invoices as they need.
Each time you edit or update an invoice, a user will be assigned to it, allowing you to determine who created it etc.
Without going deeper into the code, that's what I think you need to know.
As concern of database design, you can design something like:
You should manage a organization model where each organization must be a sub-domain and your other model like User etc.. should be associate with organization model.You can extract the subdomain name from request url (like request.host, request.subdomain etc..) and find the records as per this subdomain request.
As concern of resource permission you can use cancan gem where you can manage resource accessibility through a single file.
https://github.com/CanCanCommunity/cancancan
Hope it is helpful for your initial design.

Multiple devise models vs permission based

The application I'm building is to allow users to download vouchers. Employers sign up for an account, add employees (who get a login), select which vouchers to enable, and then employees can see the enabled vouchers and download.
I initially created two devise models: employee and employer. This was so active record associations would be simple (employer has_many employees, employee has_many vouchers). But this would also mean separate database tables and therefore separate sign in forms.
I looked into single sign in forms for multiple users and this seemed to have the consensus that you should instead have a single User model and use CanCan and Rolify for permissions. But the problem with that is you cannot (I believe?) do active record associations between these two roles (not separate models).
I next looked at subclassing so I could do associations, but it has issues as people say Rails isn't really meant to subclass, and it seems a bit hacky.
So I'm left feeling like I have to choose the lesser of evils, whereas I really just want to find the right way.. Thanks in advance for any help.
So a friend of mine solved this very elegantly for me, for everyones reference:
Good question. It’s a great problem that deals with the intersection between good engineering (model implementation, database design) and user experience (single sign in form).
Assuming that Employees and Employers differ enough, it makes sense to implement them as separate models. But it also makes sense to have a single sign in form—employees and employers shouldn’t have to care that they’re signing into the right form.
Single table inheritence usually appears to be the ideal solution, but tends to best be avoided in Ruby on Rails applications unless absolutely necessary.
I’ve actually thought about this problem before, so I would suggest an implementation along these lines:
An Employer model.
An Employee model.
A SignIn/Login/Credentials/WhateverYouWantToCallIt model.
In terms of employer/employee associations, as before:
Employee belongs_to :employer
Employer has_many :employees
Now, considering that both models are able to sign in, it makes sense to separate these credentials into their own SignIn model. If you do some reading up on polymorphic associations (http://guides.rubyonrails.org/association_basics.html#polymorphic-associations), you’ll find that they are awesome for creating relationships where the association can be with different models.
So now you need to create associations between sign in credentials and employers and employees:
SignIn :belongs_to :signinable, polymorphic: true
Employer has_one :sign_in, as: :signinable
Employee has_one :sign_in, as: :signinable
The elegance of this solution (in my opinion), is that you’re able to separate your SignIn, Employer and Employee models, which not only conforms to good Ruby on Rails conventions, but is good database normalisation practice. At the same time, you have a SignIn model that makes it trivial to implement a better sign in form experience that allows both employers and employees to sign in.

Is has and belongs to many suitable

Am new to this site, looking forward to getting more involved :)
I'm creating a customer ordering system using rails3, devise, cancan etc.
In brief, we three models:
Users
Companies
Orders
I'm struggling to understand the relationships though. Initially the users had many companies and the companies belonged to a user.
However, we actually have two sorts of user:
The admin staff here who can create companies, update details etc.
Our customers who can login and see only their companies and related orders.
I thought about creating two controllers - admin and users but it seems unnecessary and not very rails. Plus cancan can do all that I think.
What do you think we should do here? We were thinking about using the has_and_belongs_to_many relationship but most people online seem to say avoid it.
Thanks,
Jenny
--- edit ---
Thanks to all of you who've helped!
After some reading, I decided to use the has many through association.
I created a new model called agreement and set my models up as follows:
class User < ActiveRecord::Base
has_many :agreements
has_many :companies, :through => :agreements
end
class Company < ActiveRecord::Base
has_many :agreements
has_many :users, :through => :agreements
end
I'm a little stuck though and can't find a good example online.
Should I be creating a user and company separately and then create an agreement to match the two up?
Again, thanks for the help All.
Given the description it sounds like you have:
Users
Customers
Companies
Orders
The Admins are Users who have the role allowing them access to the create,update on the companies. A customer belongs to a company and may also be a 'user' depending on the information you store in the User model.
As for the HABTM it's still ok to use if you aren't putting additional data within the join table. Typically though you'll have some information in the join table since it provides additional context to the join.
A nice resource for sample data models, and to give some ideas around the Entities and relationships is Library of Free Data Models
You can go with has_many :through .As it seems application will surely need some continuous changes in the coming future.So in this case it will be helpful
Reply if any queries
Thanx
First, you need to know what you really want to achieve, understand the relationships and how the relationship needs to look like. Draw some entity relationship model on paper, that helps.
Personally, I prefer to user has_many :through because if you need to store additional data for that relation (which may be the case when extening your app) you're already set and don't need to migrate your tables and models from habtm to has_many :through.
For the user permissions, stick to cancan.

Multi - User Multi Environment

I'm looking to create an app, where each user can create their own... "Universe" in a way, with the amount of items and names that makes sense to them, etc.
I've never done this before, so far I've had the typical cases where you have users and admins, but they're both looking essentially at the same thing. Here each user will have a separate environment.
Obviously a user should not be able to see someone else's environment.
Can someone please point me to the right direction on this subject? Maybe some useful gems or resources I could use to get started?
Any advice is welcome!
I'd start with using a plugin for authentication, e.g. AuthLogic or Devise are two popular examples.
Both of these let you define a User class.
Then, when you are showing the user their stuff in their environment, you can make sure you only show them their own stuff by using has_many, and has_one, and has_and_belongs_to_many relationships in rails.
e.g. if it was facebook, you might have something like this
Class User < ActiveRecord::Base
has_many :news_items
has_many :friends
has_many :messages
end
In your code you could then refer to
#user.news_items
#user.friends
#user.messages
And the relationships would ensure you were only showing information belonging to that user.
(Caveat: in reality the relationships will be more complicated, and you will probably need more complicated logic, but this should get you started)

Resources