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.
Related
I have a Rails 3.2.22 app that I'm maintaining and I need to create a quasi-complex form. It's a form that records medications into a report.
So my thought is to build a model called NarcoticUsage to contain the record then an associated/nested Model called Narcotic which will be the actual model with the drug names.
I need to somehow within the Narcotic usage form include functionality to add multiple instances of the Narcotic model. ie. A form where you would have the drug name (from Narcotic model), then the expiration date and serial numbers of the drugs (stored in NarcoticUsage). In the form I'd like to be able to click a "+" sign or something like that to add multiple drugs. So in essence if someone recorded Tylenol, Cough Syrup, Ativan they could add a dynamic field to fill in the drug name (from narcotic), then enter the expiration date and serial numbers associated with the narcoticusage model.
I have some ideas on how to design the models and forms using nested_attributes but I'm not sure the best way to design this is.
Any thoughts on best practices with nested_forms?
Thanks in advance and if you need clarification or some sample code, please let me know.
Update: Here is my proposed model schema
narcotic_usage.rb
has_many :narcotics
attr_accessible :narcotic_id, :lot_number, :expiration_date
narcotic.rb
belongs_to :narcotic_usage
attr_accessible :name
I'm not sure if you need nested forms for this. I would have it so that you drag/add in divs representing Narcotics, each of which has a hidden field with the name set to "narcotic_usage[narcotic_ids][]" and the value the id of that narcotic.
Then, when the form is submitted, the ids of all of these will automatically go into an array accessed via params[:narcotic_usage][:narcotic_ids] and you can then update your #narcotic_usage object with params[:narcotic_usage] in the usual way. One of the methods given to you by the has_many macro is narcotic_ids=, which expects to be called with an array of narcotic ids.
In other words, if you have Tylenol with id 123 and Ativan with id 456, then doing this:
#narcotic_usage.narcotic_ids = [123,456]
#narcotic_usage.save
then rails will make the associations for you in the database. Your form's params just need to hook into this.
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.
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.
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
I have 2 models
ShippingClass, which define a shipping fare and the destinations to which the shipping fare is applicable
Shop, which has a state machine that determine if a number of actions are allowed or not
A shop has_many shipping_classes. The user can add or delete shipping classes and, among other factors, the fact that at least one shipping_class exist or not has an impact on the shop state.
The bottom line is that any time a shipping class is added/deleted/modified I run an update_state method on the shop model to keep the state up to date. What this method does is basically checking how many shipping_classes are associated to the shop and adjust the shop status accordingly (eg, to simplify the shop state is active if there is at least 1 shipping_class assigned, otherwise is inactive)
I was wondering if it is good practice to update the shop state from the controller. I am in fact evaluating the opportunity of having the ShippingClass to update the Shop upon save and destroy. While this may be more error proof, as I don't need to remember to update the Shop model every time I save a ShippingClass, it however increases the coupling of the models.
Using callbacks to do this appears not to be an option. These are wrapped into transaction.
Therefore the parent model (Shop) does not see exactly what is the status of the associated models (ShippingClasses) before the transaction is completed.
EDIT
Another option, as pointed out below, is to place the model update into an observer. The advantage of this is that it is not wrapped into a transaction, so the Shop model should be able to check the associated ShippingClasses. The disadvantage is that is not wrapped into a transaction, so a failure to update the Shop model would desync the Shop status. This would, however be better than placing the update into the controller, as it would be done once forever.
Another option could be override the save and destroy methods of ShippingClass and update the Shop model from there.
What is the best practice and why?
THanks in advance
As you pointed out, keeping the logic in the model is best since it will then apply any time a controller attempts to modify/delete/add a ShippingClass. Within the model, I would look to use a callback on ShippingClass - have the ShippingClass update the state of any Shops that are affected as a result of the modify/delete/add operation.