Dynamic nested form in Rails - ruby-on-rails

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.

Related

How do I save two models with has_many through on the same form

I've had this question about ruby on rails some time ago, and managed to solve it in some way:
The solution I've found is use nesting forms with the join model(fields_for), saving the third model within an external form and inserting its ID with ajax.
The problem is that the nested form is too big to nest inside Order form(main form).
I'm not satisfied with this solution, so here it is:
Let's say I have three models:
Order
Order-List (has_many through model)
List
So, the Order contains different Lists, and each List has Items (With other has_many relationships between).
In an example, know that I can save the information about the has_many through model on the same form, but how do I save an Order AND a new List(on the same form)?
Thanks in advance!

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.

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.

How does the Rails' single table inheritance works?

I have a user table, and a teacher that I newly created. The teacher is sub class of user, so, I use scaffold generator to generate the teacher table, than, I modify the model to do teacher is subclass of user. After all that, I did a db:migrate. Then, I go to
http://localhost:3000/teachers/new
It shows an error:
undefined method `teacherSalary' for #<Teacher:0x103331900>
So, my question is what did I do wrong? I want to create a page for doing user register, the user can ONLY be a teacher / student. But I can't add a teacher record ... ... Moreover, I go to
http://localhost:3000/users/new
I want to have a combo box that allow user register their user to be a "teacher" or a "student". But everything seems not work like I expected. What I need to do? Thank you very very much for your help.
Within your database you should have a single table called users. This table should have a string column which by default is called type. If you use another name for this column then you will have to set the inheritance column name manually using self.inheritance_column = "column_name"
Within your application you have three models, User, Student and Teacher. User inherits from ActiveRecord::Base as usual, Student and Teacher both inherit from User.
You should then be able to instantiate new Teacher and Student objects. Internally this works by writing the model name to the type field on the user tables and then when you use Student.find it adds a clause to the SQL to only return rows where the type = 'Student'
You can add shared behaviour to the User class, e.g. validations etc then add additional behaviour to the inherited classes.
A fuller description of how STI works can be found in Martin Fowlers Book(Patterns of Enterprise Application Architecture).
I found this definition really handy:
STI means one table contains the data of more than one model, usually differentiated by the "type" column. ("users" table contains data for the models "Teacher", ""Pupil", "Employee", "Assistant", etc.)
Keeps similar models in the same table instead of creating new ones.
A Polymorphic Association means that one model can be associated with more than one other model(Comment can belong to post, image, file, user_type...)
To prevent foreign key conflicts, the association is reperesented with the *_id and *_type columns instead of only *_id.
For what you have here , I am not sure if STI is the best way go . STI should generally be used when there is a OO like inheritance and the Models have the same Attribute but different behaviour . In your case Teacher and Student can sure have a few shared attributed , but they are also bound to have different ones as well .
You might want to experiment with a polymorphic association as well .

Setting default values across multiple children in a multi model form (Rails 2.3 )

Am trying to simplify the create / edit view for a multi-model controller.
User can dymically add / remove child input fields from the form. (Have followed Eloy's complex form example)
I want to limit the user's ability to set certain attributes across multilpe children..
Suppose I have a child attribute with and I want the user to only input the date once.. eg the date will be the same across all children..
I would like present a single date entry box and then multiple Adults | Seniors boxes depending on the number of children the user wants to submit.
using accepts_nested_attributes_for my form is showing multiple date boxes..
(Since I want to retain the ability to do this as an admin I don't want to move the date attribute to the parent.)
How should I go about adapting the form without having to extend the controller logic too much?
If you have business logic that states that all of your children models have the same date, then I see this working a couple different ways.
First of all, maybe you have your data in the wrong place. If the date is always going to be the same for all of the children models, then why not make it an attribute on your parent model instead? You can always use the delegate method in your children model to fetch the date from the parent.
Another way I see of handling this is with a virtual attribute and a callback on your parent model. Use attr_accessor to create a virtual attribute on your parent model. Then in your form, add a field for the date to the parent model with the name you used to define the attr_accessor. Finally, add in a before_save callback (or whichever callback is appropriate for your case) in the parent model that saves the date to all of the children.

Resources