Rails 3.2 Event Logging - ruby-on-rails

I have a rails application with an administration interface that allows a user CRUD operations on certain models. The client wants a way to log what user does what to each model. For example, A user deletes a customer etc. He would like to track who deleted/updated/created that customer. I'm pondering the best way to handle this. I'm also curious if there is a gem out there that already does this.
Here's my thinking.
I could have a created_by and updated_by field in each Model. The problem
is tracking deleted_by. One Method is to mark the Customer inactive
instead of deleting the actual record. Seems cumbersome and there
would be a lot of repetition in each and every model I want to
track.
I could create an event_history model that tracked the following fields (class diagram below). The model_record_data field could be stored as an array or object possibly? Can you store objects in a mysql field as text? The benefits of this method, to me is that I can call to this Model and store actions from any model I create in the future. In addition I can restore a record to a previous state if someone makes a mistake.
event_history ->
model_name
model_record_data
action #create/update/delete etc
action_date #datetime
user_id
I would appreciate some feedback on this and your help would be appreciated.

Take a look at this gem (audited). I believe it does what are asking.
https://github.com/collectiveidea/audited

Related

Rails: Working on (Updating) 2 different controllers at the same time

I want to implement a simple discount coupon. I have a model that valid coupons are saved (beside some other things) and a Product model that product features are stored (name, price, ...).
I have a simple form that enables the user to enter his coupon. I should check it to see if it is valid or not (I defined a scope for it). If the entered coupon is valid, I have to update both of the mentioned tables. In the first one, I have to change the coupon to "used" and in the second table, I should update the price with the new value. And I want to do these operations when the user entered a value in the form.
What is your suggestion and solution to do both of them? As these two operations are related to 2 different models and controllers, I cannot access them in one controller. What is the best way to call a method to do these operations? Could you please give me a clear explanation?
You have access to both models in either controller however to do this the "rails way" you should put this logic in your model. I would add a before_update callback in your coupon model that checks if the coupon is being changed to "used" as you mention. If so, you can then update its "price" in your product table. The key concept to takeaway from this is that you can call all Models from anywhere and they are not limited to their respective controllers only.

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

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.

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.

Ruby on Rails: When to add a new resource

I have two questions on how the MVC works. I'm pretty sure I should add several resources, but I'm just coming to this conclusion and wanted to ask first to get a better understanding.
First question:
I have two models, user and subject. Users can enter subjects into the database. For each subject there are 5 data entry forms (Baseline, 3month, 6month,...) that are about 100-200 questions each (The relationship would be each subject has 1 of each data entry form). Should each data entry form be a new resource?
Second Question:
Lets say I want to randomize a few subjects into a group:
From the view, the user enters the amount of subjects to be randomized into a group, as well as the group name to be assigned. The form tag specifies an action I created, just for this function, called randomize.
From the controller, randomize uses the params sent from the view to query the database, and then to update each record to reflect the group. Instead of creating a new action for the randomize function, should I create a new resource for it? And as a side note, should any of these calculations be done in the model (other than defining the variables)?
Thank you for your time. Any help would be greatly appreciated. I am officially over-whelmed by all of the information I'm learning about this...but I feel that I'm really close to actually understanding the MVC.
I'll answer your second question first.
You should be creating controllers to handle CRUD tasks for resources. In this question you ask about creating a "Group". Regardless of whether this is an actual resource, or just a modification to a collection of other resources, you have the concept of creating a "Group", probably reading/updating a "group" and certainly deleting one.
Based on this, I would rather have a RandomGroup controller which I can call using a standard REST interface, rather than some #randomize action stuffed in the side of another controller.
As for your first question ... maybe, maybe not.
It really depends on whether an data entry form has any business logic of its own. If it doesn't then there's no harm it being part of a large object. But if your tests and code start to become too complex within the Subject model you may want to split it out into multiple models or at least multiple modules included into that model.
Perhaps you could consider that "Baseline", "3month", "6month" are all the same ... aside from their lead time. Perhaps that is a model in itself, and Subject could has_many :forms ??
Food for thought.

MVC Validation using Data Annotations - Scenarios where it doesn't work, Alternatives?

So I have been using data annotations for my validation in an MVC project and they seem to work in most scenarios.
Here are two examples in my current project where they don't seem to fit and I am unsure of the best place to put the validation.
1) I have a Join League page that contains a form where the logged in user enters their team name and clicks to join the league. When they submit the form i need to make sure that the current user doesn't already have a team in the league. So it basically needs to query the db for that user id and league id to make sure no team exists for the user. My ViewModel does not contain user id, since it is not relevant to the view.
2) On this same page, I also need to make sure the team name is unique. This is easy if you are just looking to see if it exists in a table. You create a custom validation attribute that query's a table for the value of the field. However i need to see if it exists in a table for a certain league id. (the league they are joining.)
It doesn't seem like Data Annotations are an ideal solution for anything other then trivial validation. My current solution is to query the db at beginning of post action method, and add the error to the ModelState manually. (yes, terrible)
Any ideas?
I think it may help to put some thought into the difference between Input Validation and Business Logic. Ayende has some thoughts on this here
Rules like 'When they submit the form I need to make sure that the current user doesn't already have a team in the league' sounds like Business Logic, not Input Validation, and you may want to handle it in a different way. This logic could, for instance, go into a 'CanSave' method on a 'User' class or something similar - the key thing is to separate this from Input Validation if you can.
Although I agree with Steve, DataAnnotations has a base ValidationAttribute in which you can implement anything you want. To say it can only do trivial things is not accurate in fact with this extensibility point you can do almost anything you want.
Now there are some issues with service location being all over the place by having database logic inside your code but there are options to clean this up. The DataAnnotations are applied via a ModelValidatorProvider class that can easily be configured just like you would do ControllerFactories or ViewEngines.
ModelValidatorProviders.Providers.Add(new YourCustomProvider());
Now what you can do in this case is have your validator provider provide the persistence layer code into your attribute. So the code stays clean yet you can use custom data annotation attributes that touch the db.

Resources