Reputation: 5217
I'm undertaking a rather large conversion from a legacy database-driven Windows app to a Rails app. Because of the large number of forms and database tables involved, I want to make sure I've got the right methodology before getting too far.
My chief concern is minimizing the amount of code I have to write. There are many models that interact together, and I want to make sure I'm using them correctly. Here's a simplified set of models:
class Patient < ActiveRecord::Base has_many :PatientAddresses has_many :PatientFileStatuses end
class PatientAddress < ActiveRecord::Base belongs_to :Patient end
class PatientFileStatus < ActiveRecord::Base belongs_to :Patient end
The controller determines if there's a Patient selected; everything else is based on that.
In the view, I will be needing data from each of these models. But it seems like I have to write an instance variable in my controller for every attribute that I want to use. So I start writing code like this:
@patient = Patient.find(session[:patient]) @patient_addresses = @patient.PatientAddresses @patient_file_statuses = @patient.PatientFileStatuses
@enrollment_received_when = @patient_file_statuses[0].EnrollmentReceivedWhen @consent_received = @patient_file_statuses[0].ConsentReceived @consent_received_when = @patient_file_statuses[0].ConsentReceivedWhen
The first three lines grab the Patient model and its relations. The next three lines are examples of my providing values to the view from one of those relations.
The view has a combination of text fields and select fields to show the data above. For example:
"val1", "val2"=>"val2", "Written"=>"Written"}, :include_blank=>true )%> :force %>(BTW, the select tag isn't really working; I think I have to use collection_select?)
My questions are:
Thanks in advance, Aaron.
Upvotes: 0
Views: 151
Reputation: 3950
Do I have to manually declare the value of every instance variable in the controller, or can/should I do it within the view?
As a general rule of thumb, you should avoid defining instance variables in your views; especially if it's call to a model. It can be confusing to maintain, more difficult to test and cannot be reused.
What is the proper technique for displaying a select tag for data that's not the primary model?
Provided that the "secondary" models are associated with the "primary" model, you can chain methods together. When you define an association in your model, you'll get these methods for free.
# Where attr is an attr belonging to the patient_address which is
# associated with the patient
<%= @patient.patient_address.attr %>
When I go to save changes to this form, will I have to manually pick out the attributes for each model and save them individually? Or is there a way to name the fields such that ActiveRecord does the right thing?
You will be interested in the fields_for method for nesting associated models in a single form. Railscasts also has some great examples of working with associated models in forms.
Upvotes: 2
Reputation: 7656
1)
There is nothing stopping you from writing arbitrary Ruby code in the view, so you can just write @patient.PatientAddresses
, instead of defining @patient_addresses
in the controller. That is just boiler-plate anyway and very easy to refactor with search/replace, if you wish to change it later. OTOH I would put the line
@patient = Patient.find(session[:patient])
in the controller, since you only want to perform the look-up once and the query might also change.
3)
The save
method in ActiveRecord
is a bit subtle. In general, it will save only the object on which you invoke the method as well as any dependencies. It may not be possible to save just one row, if that row has a foreign key relation with another table. This means that for the code
patient = Patient.new; file_status.patient = patient
patient
would be saved automatically when calling file_status.save
, since the id
for patient
must be generated for the foreign key relation. Calling patient.save
would not save file_status
however.
If you want the associated objects to be saved along with the Patient
you can specify :autosave => true
when defining the has_many
relation.
The details are in the docs.
Upvotes: 0