Designing a Database Schema - Data that is common to all users or custom made - ruby-on-rails

Hi I am working on a calendar application using Ruby on Rails. Rails is database agnostic, so in development I'm using SQLite but in production I am looking to use PostgreSQL.The current obstacle that I am facing is with the way I am designing my database schema.
First I have a users table that holds information such as login info and email. Each user has_many plans.
Then I have a plans table that belongs_to users and each plan has an event it references, the date, start time, and end time.
So the plan tables would reference the events table.
Here is my issue:
I would like to have two event tables. One is custom events. The other is default events.
The default events is just a list of common events already defined so the user can already select from a list. The custom events table is a list of events created by a user that references their id.
Here is my solution:
Would it be sufficient to add a new boolean column to the plans table called "custom". And if it is true then the event_id (in plans table) will reference the custom events table, and if it is false then it will reference the default events table. Is this a valid solution and if so, how would I implement it into my Rails application?
Thank you for taking your time to read my question. I am sorry I am an idiot. I am practicing everyday to be better.

Try to not think in terms of tables first, but in terms of classes and the behavior of their instances. What would matter most in the end is not how many tables your design has, but whether the responsibilities have been correctly attributed to the different classes in your model.
In this case it looks like you need two different classes, because some events will belong_to a user and other won't. The former will be created, modified and deleted by that user, and the latter will be managed by an admin. The instances of those classes can be stored in the same table using STI (Single Table Inheritance), with a string column named 'type' to enable Rails to store the class for each instance. The UserEvent class will belong_to :user, and the DefaultEvent won't. Both classes can extend Event, which in turn extends ActiveRecord::Base.
Please let me know if you need additional clarification.

Related

How to handle a single form to update multiple unrelated models?

I am working on a legacy Rails 3.2 application that has a lot of settings a user can manage. Settings are associated with 3 types of model in the system: User, Company and CompanyUser. In order to avoid having to write database migrations each time a new type of setting is added
I've essentially created a key/value store (1 row for each setting) that has a polymorphic association with each of the above mentioned models. A base Setting class handles all of the common functionality like setting the key, relationships etc. each type of setting extends the base class and can contain it's own validation and/or logic. For example:
class Settings::EmailSignature < Setting
validates :whatever
end
For any model that requires a setting I've implemented a has_setting helper method that sets up the association and provides some delegates to directly get and set the setting without needing to go via the associated model object, the User model might look like:
class User < ActiveRecord::Base
has_setting :email_signature
end
This side of the code is working well, however the problem I have is when I create the form for the settings. For the user it might make sense to have User, Company and CompanyUser settings mixed together in the same form. Using nested attributes doesn't feel like a good solution in this situation as the settings are not related and there is no common parent object. I've considered using a form object to handle mapping each setting to the correct object but that doesn't feel like a great option either as each setting would require knowing it's id, the associated records id and it's type. This would not be particularly easy to manage when building the form.
I'm about to go down the route of having each setting in it's own form and having the record save automatically as the user edits each item. This would mean only a single record is ever saved at a time and will make things much simpler at the controller layer and also provide a lot of flexibility in how settings a grouped. Before I go down this route I wanted to see if there are any other options for submitting a single form in a single transaction that I may have overlooked?
Please note, this application is written in Rails 3.2 and is not in a state in which it can be easily upgraded to Rails 4 right now so any solutions need to work with Rails 3.2.

has_many :through model names, controller and attributes best practices?

Disclaimer: I really spent time thinking about names of models and variables. If you also do, this question is for you.
I have a Rails project which contains two models: User and Project.
They are connected by the model ProjectsUser, which is a connection model in a many-to-many relationship. This model also holds the role of a user in the given project, along with other attributes such as tier and departments. So this is a has_many :through relationship.
Given this scenario, here is everything that always bothered me on all my rails projects since I started developing on it:
Should I use a ProjectsUserController or better add the relevant actions on UserController and ProjectController? At some point, I want to assign users to a project, or even changing the role of a user in a given project. Is it a better practice to leave those actions on the connection controller, or use the model controllers?
Should I write a method to get the role of a user for a given project? This is basically if I should have a method User#role_for(project) or not. Since this method basically is getting the information from the projects_user object it could make more sense to always let this explicity on the code, since most of the times I'll have the project and the user, but not the projects_user. Is this line of thinking correct, or maybe the problem is that I'm should have more project_user on my code than I really do? Are there good caveats for this?
Should I try to rename my table to a non-standard name if it is not obvious? Ok, I got that if I have the models User and NewsSite I should use has_many :subscriptions, but the thing is that naming those models in real life cases are usually harder, by my experience. When the name ends up not being that obvious (for exemple, in my case, maybe project_participation as #wonderingtomato suggested) is for the best, or in those cases it is better to fall back to the ProjectsUser approach?
One extra cookie for pointing beautiful open source Rails code, or by book indications that might help with my kind of questions.
I would use a specific controller. Even if now the interaction sounds simple, you can't know if in the future you'll need to add more advanced features.
I've been handling these kind of relationships in several projects, and using a controller for the join model has always paid off.
You can structure it this way, for example:
index should expect a params[:project_id], so that you can display only the index of users for a specific project.
create is where you add new users, that is where you create new join models.
update is to modify a value on an existing join model, for example when you want to update the role of a user in a project.
destroy is where you remove users from the project, that is where you delete the corresponding join models.
You might not need a show and edit actions, if you decide to manage everything in the index view.
Also, I'd suggest to choose a different name. Rails relies heavily on naming conventions, and projects_users is the default name for the join_table you would use with a has_and_belongs_to_many association. In theory you can use it for an independent model (and a has_many through:), but it's not immediately clear and you might break something. In addiction, it will confuse the hell out of any new programmer that could join the project in the future (personal experience).
What about calling the model something like project_participation?
If you haven't built a lot of functionality yet, and don't have yet that table in production, changing it now will save you a lot of headaches in the future.
update
1) I stand by what I said earlier: your join model is a full fledged record, it holds state, can be fetched, modified (by the user) and destroyed.
A dedicated controller is the way to go. Also, this controller should handle all the operations that modify the join model, that is that alter its properties.
2) You can define User#role_for(project), just remember that it should properly handle the situation where the user is not participating to the project.
You can also make it explicit with something like:
#user.project_participations.where(project_id: #project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: #project.id, user_id: #user.id).try(:role)
But I'd say that encapsulating this logic in a method (on one of the two models) would be better.
3) You are already using a non standard name for your table. What I mean is that it's the default name for a different kind of association (has_and_belongs_to_many), not the one you are using (has_many through:).
Ask yourself this: is the table backing an actual model? If yes, that model represents something in the real world, and thus should have an appropriate name. If, on the other hand, the table is not backing a model (e.g. it's a join table), then you should combine the names of the tables (models) it's joining.
In my mind, REST doesn't always have to map directly to DB records. A conceptual resource here is the association of Projects to Users. Implementation would be different depending on your persistence layer, but a RESTful API would be standard.
Convention over Configuration in Rails is a great helper, but it isn't necessarily applicable to every case 100% of the way through the stack. There doesn't need to be a 1-to-1 mapping between controllers, models, and their respective names. At the app-level, particularly, I want my routes/controllers to represent the public view of the API, not the internal implementation details of the persistence and domain layers.
You might have a UserProjectsController which you can perform CRUD on to add/remove project associations to users, and it will do the appropriate record manipulation without being overly bound to the DB implementation. Note the naming, where the route might be /user/:id/projects, so it's clear you are manipulating not Users or Projects, but their associations.
I think thinking about this sort of thing (both before and after the fact) is what leads to better designs.
I too start with the model and think about the application structurally. The next step in my oppinion is to build the user interface to make sense based on what makes it easy and useful for the user (spending more effort on things that matter more). So if it makes sense for the user to separately edit the ProjectsUser objects then the ProjectsUsersController is the way to go. More likely editing the join model objects as part of the Project (or User depending on the structure of you app) will be a better fit for the user. In that case using a nested form and editing via the controller (and model) that's the main model referenced by the form is better. The controller really lives to serve the UI, so decisions about it should be dependent on the UI.
Yes, if it makes your code simpler or more readable. If you use role more than once I suspect it will.
I would actually name that model something like Member, or ProjectMember (or Membership). It defines a relationship between a user and a project, so its name should reflect what relationship that is. In the occasions where such a name is too unwieldly or too hard to define then falling back to something like ProjectUser is reasonable (but not ProjectsUser). But I definitely like finding a more meaningful name when possible.

Common identifier for multiple models in Rails

I'm developing a simple app for creating and managing events such as birthdays, weddings etc. All of the different events have different attributes and could be very different. I'm a beginner in rails but I've done the Rails for Zombies course so I know how to create models/controllers. However, I'm stuck now when I want a common identifier for all the events, like a key. It should be possible to search for events using a code/identifier and I don't know how to do this.
I was thinking of having an Event model which would contain the identifier, ex 'JamesBDay'. Then each of the different event model (Birthday/Wedding etc) would keep it's respective Event model. Am I thinking right and how do I do this using Rails 'generate' and 'db:migrate' commands?
And when this is accomplished, how do i search for any type of event using the identifier in their Event attribute?
An explaining picture below
Thanks!
This sounds like a perfect problem for Single Table Inheritance. Essentially you would have a user that has_many events. Create an events table and add a field called "type". From there you create other models that subclass "Event" and NOT "ActiveRecord::Base". These will all be stored in the same table, but will be unique objects that can have their own methods. This allows you to parse through the events as an entire list "Event.all" and then find out the type there, or you can parse through individual event types with "Wedding.all".

Aggregating Data in Rails 3

I want to aggregate data from different sources, Twitter lastfm and that sort. I just can't figure out how to store the data. Clearly in a database but I can't figure out how abstract to make the table to hold all this data without compromising the logical understanding of the data in each column.
I was wondering if anybody else had experience with this and now they tackled it in rails.
One option, if you want to stick with SQL, would be to have a Model/Table which contains fields common to every data source (title, url, summary) which is associated to other Models/Tables which contain the fields specific to individual data sources. The associations could be regular or polymorphic. And if you wanted to get in to some metaprogramming you could use method_missing to delegate method calls for fields not present in the 'common' Model to the associated models. This would work best with a polymorphic join. Psudeo-code:
class DataSource
belongs_to :data_source_extension, :polymorphic => true
def method_missing(method)
if data_source_extension.responds_to? method
data_source_extension.send(method)
else
super
end
end
end
The other option would be STI, so one table with all fields and a 'type' field which tells Rails which model the record should be wrapped in. This depends on how many different sources you have and how different they are from each other.
If the fields don't need to be searchable storing a Hash in a Text field works well. See Serialize and the attr_bucket gem.
Or if you want to trendy a NoSQL type database allows on-the-fly fields to be generated.
What you need is a document-oriented database (I recommend you MongoDB), and then having a set of adapters, one for each type of provider.
Document oriented database

What is Ruby on Rails ORM in layman's terms? Please explain

I am having trouble understanding ORM in Ruby on Rails. From what I understand there is a 1:1 relationship between tables/columns and objects/attributes. So every record is an object.
Also what exactly is a Model? I know it maps to a table.
What I'm really after is a deeper understanding of the above. Thank you in advance for your help
I'm a Web developer going from PHP to Ruby on Rails.
"From what I understand there is a 1:1 relationship between tables/columns and objects/attributes. So every record is an object."
That is not exactly correct, unless you use the term "object" very loosely. Tables are modelled by classes, while table records are modeled by instances of those classes.
Let's say you have a clients table, with columns id (autonum) and name (varchar). Let's say that it has only one record, id=1 and a name="Ford". Then:
The DB table clients will map to the model class Client.
The record will map to a model instance, meaning that you have to create the object and assign it to a variable in order to work with the record. The most common way would be to do ford = Client.find(1)
The two columns of the table will map to methods on the ford variable. You can do ford.id and you will get 1. You can do ford.name and you will get the string "Ford". You can also change the name of the client by doing ford.name = "Chevrolet", and then commit the changes on the database by doing ford.save.
"Also what exactly is a Model? I know it maps to a table"
Models are just classes with lots of very useful methods for manipulating your database. Here are some examples:
Validations: Besides the typical db-driven validations ("this field can't be null") you can implement much complex validations in ruby ("this field must be a valid email" is the most typical one). Validations are run just before you invoke "save" on a model instance.
Relationships: The foreign keys can also be mapped onto models. For example, if you had a brands table (with its corresponding Brand model) associated via a foreign key to your ford client, you could do ford.brands and you would get an array of objects representing all the records on the brands table that have a client_id = 1.
Queries: Models allow you to create queries in ruby, and translate them to SQL themselves. Most people like this feature.
These are just some examples. Active record provides much more functionalities such as translations, scoping in queries, or support for single table inheritance.
Last but not least, you can add your own methods to these classes.
Models are a great way of not writing "spaguetti code", since you are kind of forced to separate your code by functionality.
Models handle database interaction, and business logic
Views handle html rendering and user interaction
Controllers connect Models with Views
ORM in Rails is an implementation of the Active Record pattern from Martin Fowler's Patterns of Enterprise Application Architecture book. Accordingly, the Rails ORM framework is named ActiveRecord.
The basic idea is that a database table is wrapped into a class and an instance of an object corresponds to a single row in that table. So creating a new instance adds a row to the table, updating the object updates the row etc. The wrapper class implements properties for each column in the table. In Rails' ActiveRecord, these properties are made available automatically using Ruby metaprogramming based on the database schema. You can override these properties if required if you need to introduce additional logic. You can also add so-called virtual attributes, which have no corresponding column in the underlying database table.
Rails is a Model-View-Controller (MVC) framework, so a Rails model is the M in MVC. As well as being the ActiveRecord wrapper class described above it contains business logic, including validation logic implemented by ActiveRecord's Validation module.
Further Reading
Rails Database Migrations guide
Rails Active Record Validations and Callbacks guide
Active Record Associations guide
Active Record Query Interface guide
Active Record API documentation
Models: Domain objects such like User, Account or Status. Models are not necessarily supported by a database backend, as for example Status can be just a simple statically-typed enumeration.
ActiveRecord:
Provides dynamic methods for quering database tables. A database table is defined as a class which inherits ActiveRecord class (pseudo-PHP example):
class User extends ActiveRecord {}
//find a record by name, and returns an instance of `User`
$record = User::find_by_name("Imran");
echo $record->name; //prints "Imran"
//there are a lot more dynamic methods for quering
New records are created by creating new instances of ActiveRecord-inherited classes:
class Account extends ActiveRecord {}
$account = new Account();
$account->name = "Bank Account";
$account->save();
There are two pieces here: the ORM and Rails's MVC pattern. ORM is short for "object-relational mapping", and it does pretty much what it says: it maps tables in your database to objects you can work with.
MVC is short for "model-view-controller", the pattern that describes how Rails turns your domain behavior and object representations into useful pages. The MVC pattern breaks down into three chunks:
Models contain a definition of what an object in your domain represents, and how it is related to other models. It also describes how fields and relationships represented in the object map to backing stores (such as a database). Note that, per se, there's nothing about a model which prescribes that you have to use a particular ORM (or even an ORM at all).
Controllers specify how models should interact with each other to produce useful results in response to a user request.
Views take the results created by controllers and render them in the desired way. (By the time you get to your view, you should mostly know what's being rendered, and there should be very little behavior happening.)
The definition from Wikipedia:
Object-relational mapping (ORM, O/RM,
and O/R mapping) in computer software
is a programming technique for
converting data between incompatible
type systems in relational databases
and object-oriented programming
languages. This creates, in effect, a
"virtual object database" that can be
used from within the programming
language.
From a PHP view it will be in the following way(via example)
Connect to the database and get some row from posts table.
Turn that row to an object with attributes like those in the table columns.
If the posts has comments in comments table, you can also do post.comments and you get the comments also as an array of objects as well.
You can define relationships between tables like saying: Posts has_many Comments, a Comment belongs to a post and so.
So basically you are not working with database rows, instead you turn those rows and their relationships to objects with composition or inheritance relationships.
In layman's terms.
A Rails Model is proxy to a table in the database. These models happens to be Ruby classes.
The objects of these classes are proxies to rows in the table of which this model is a proxy.
Finally the attributes of these objects are proxies to the column data for that particular row.
Above is actually the Rails ActiveRecord ORM.
1:1 is not quite correct, since there is object-relation impedance mismatch.

Resources