I have a form that needs to be able to interact with 5 (and possibly more) models. It is the following:
Patient - Needs to create the patient record and details (Name, address, etc.).
Form - Keeps track of form name and version.
Questions - Keeps track of questions attached to each form.
Answers - The answers to the questions that the patient gives.
Form Response - Keeps track of the patient that filled out the form, and what form it was.
I've created a layout of the models and what I'm thinking the data would look like:
Google Doc - DB Layout
On the Form Response, the completed_by poly relationship is taking into account that a user, third party, or patient can fill out a form
I am stuck on the best way to go about doing all of this through one form. Right now I am going through the patient controller and patient/new view because I picture this all being related to a patient. I'm just not exactly sure how to do all of this nesting inside the form itself (form_for, form_tag, fields_or?) and then dealing with that in the create action of the controller. Even after going over a bunch of railscasts etc, I'm still very stuck. Any insight would be much appreciated.
Well here is what I can understand from the question. There will be five models
Patient, Form, Question, Answer, Formresponse
Now a Form will have many Questions. A Question will have many Answers. A Formresponse will have many Answers.
The model structure should be
class Patient < ActiveRecord::Base
has_many :formresponses
end
class Form < ActiveRecord::Base
has_many :questions
has_many :formresponses
end
class Question < ActiveRecord::Base
belongs_to :form
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
end
class Formresponse < ActiveRecord::Base
belongs_to :form
belongs_to :patient
end
Now you will have one form for creating/editing patient information, which should be straightforward as no nesting is there.
The creation of Forms will be tricky. Storing attributes of the class Form will be straightforward. To store attributes of the class Question, you would need to handle them in the controller. create form elements such that the name is binded to "questions"
eg,
<input type="text" name="questions[0][name]" value="some name" />
<input type="text" name="questions[0][help_text]" value="some help text" />
note - name and help_text are attributes of your model Question
Now in the controller you can iterate through each value of params[:questions] to get the induvidual form value.
so, there it will be something like this
params[:questions].each do |question|
q = Question.new(question)
#form.questions << q #This will append the question to your #form instance
end
...
#form.save
Similarly you can do this for storing responses. I hope its a bit clear to you now
Related
I'm relatively new to Ruby on Rails.
I have an app where the User can create Forms.
I've already declared that user has_many forms and forms belongs_to user.
In addition, Forms have a nested model Item which stands for the questions of the Form, allowing a User to make a Form to have multiple questions. Also, Item has_many Answers so one question can have multiple answers (like radio or checkbox type of question). Finally, an Answer has_many Results allowing to store multiple values later for each answer if it is submited by different people.
Users also have Children which I'd like them to apply the Forms that they create.
How can I achieve this?
Would you recommend to create an association between my Child model and Form model?
How would you do it?
So all I need is to have the forms created by one user available to be answered for each one of the user's children.
Update:
So I came up with the following idea:
Create a join table between form and children to map which forms were applied to which child.
Also, the result model should have an answer_id column of the answer which it responded to. And I guess it will need another column to point the id of the join table above to map which form-child belongs to.
¿Do you think this logic is right?
When displaying the form to be used, I plan to display form.title, loop into their items through each item and display its item.title and again loop into its answers through each answer and display its type and label as of the type of field and label for the form_fields of each of the results.
The problem now is how can I manage to do this?
I know how to create and save specific number of Objects but not Dynamic number of Objects.
Code:
form.rb
belongs_to :user
has_many :items, dependent: :destroy
accepts_nested_attributes_for :items, allow_destroy: true
item.rb
belongs_to :form
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, allow_destroy: true
answer.rb
belongs_to :item
Let me point out what may be the problems in your current schema:
Answer has_many Results allowing to store multiple values later for each answer if it is submited by different people
=> What happens if we want to query how many correct answers in Form for a specific User or how many correct answers in total for a Form?
Users also have Children which I'd like them to apply the Forms that they create
=> This is kind of confusing, between User and Form we have the relations: User can create many Forms and User can apply many Form via a model Children
I have researched on kind of this problem before, here is my suggested schema:
Explanation
User has many Form by creating action
Form has many Item
Item has many Question
Question has many Answer (An answer is correct/incorrect)
User applies 1/many Form, each time like that, an AnswerSheet was created between User and Form
AnswerSheet contains many SelectedAnswer so SelectedAnswer belongs to AnswerSheet and original Answer. Additionally, a SelectedAnswer was created by the action that user selects an Answer
This is clearer, we can explain the schema with the real meaning, hence, it is easier to understand & implement
One note I use AnswerSheet instead of your idea of Children, I think that makes sense, you can any term you want, but just make sure people understand it :)
According to your Scenario ,I would like to recommend you there is many to many relationship between children and form and also child has_many results.
I have a Review model. My users should be able to write reviews. The view for the Review#New should be a form with textfields that the admin creates beforehand.
In other words, my admin-user should be able to create multiple instances of a Review model that has different fields, perhaps even of different input types (string, integer, etc.). That way, when a regular user logs in, they see the different form fields that were specified for data collection by the admin user.
Naturally all of that should be stored in the DB for retrieval within the context it was stored (aka for that specific model).
What's the best way to approach this in Rails?
Think of it like a survey form, and a survey form builder.
It would be good if I could do this with Simple-Form, but that's not a requirement.
Edit 1
Here is an example of the type of fields that they should be able to add to a review:
In my experience a good portion of database design is helped by simply finding the right name for things. In your case I think you are on the right track with thinking about surveys or quizzes.
Check out the survey gem for ideas. In it the base model is Surveys. Surveys have many Questions. Questions have many Options. Surveys also have many Attempts which are answered surveys. Attempts then have many Answers.
So the corollary for you could be to have Reviews/Evaluations (created by admins) which might have many Criteria/Inquiries (possibly of different types, but we'll get to that in a minute). Then your users would create Responses/Assessments which would belong to a specific Review/Evaluation and have many Answers/Responses.
For different question types (Short Answer, Likert Scale Rating, 1-10, Tag List, etc) you could use polymorphism on the criteria/inquiries.
Hopefully some of these names I've used will help you. Feel free to use a thesaurus for more inspiration.
EDIT Re:Polymorphism
Disclaimer: polymorphism might be overkill depending on your application.
Sure, I'll expand some. Not exactly. Take a look at the rails guide on polymorphism if you haven't already. I think what you would want is
class Criterion < ActiveRecord::Base
belongs_to :askable, polymorphic: true
end
Then then I would make a model for each question/criterion type. For example:
class ShortAnswer < ActiveRecord::Base
has_many :criteria, as: :askable
end
class Likert < ActiveRecord::Base
has_many :criteria, as: :askable
end
Side note: If rails does not properly pluralize criterion to criteria you may need to add the following to your config/initializers/inflections.rb file
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'criterion', 'criteria'
end
Scratch solution.
From my experience the easiest solution is to use hstore, json or jsonb type of fields.
This solution play good with Postgresql database.
To achieve this approach you need to add field to your Review model.
Migrations:
# Reviews
def change
add_column :reviews, :structure, :json
end
# Answers
def change
add_column :answers, :values, :hstore
end
Then you can define model ReviewStructure plain ruby class, here you can use Virtus gem to serialize it easely:
class ReviewStructure
include Virtus.model
attribute :fields, Array[Field]
class Field
include Virtus.model
attribute :name
attribute :type
end
end
Then define in Review the serialization for structure field:
class Review < ActiveRecord::Base
...
serialize :structure, ReviewStructure
end
Then you can access structure fields of review with review.structure.fields.
In view you can use a simple form
<% simple_form_for #answer do |f| %>
<% #review.structure.fields.each do |field| %>
<% f.input "values[#{field.name}]", as: field.type %>
<% end %>
<% end %>
To access answer results just use:
answer.values.each do |field_name, value|
...
end
Note:
As for admin for it's better to handle creation of review structure on client side(using js), and post pure JSON structure via API.
With such approach you will have ability to create quizzes with different types of field.
Note:
Please keep in mind that current implementation connect one review to one answer, assuming that the answer model contains all the values of user response.
I have been trying to wrap my mind on a polymorphic structure for my app for a while now, but I can't get it, and I don't know how to solve it.
I have a Supplier model, and a supplier's profile can by a Company OR a Person as listed below.
Supplier Model
class Supplier < ActiveRecord::Base
belongs_to :profile, :polymorphic => true
accepts_nested_attributes_for :personable, :allow_destroy => true, :reject_if => :all_blank
end
Company Model
class Company < ActiveRecord::Base
has_one :supplier, as: :profile
end
Person Model
class Person < ActiveRecord::Base
has_one :supplier, as: :profile
end
On the Model level (on console) my associations works fine, but I have to those between the two model up front (supplier.profile = Company.new, for example).
What I want is, when a user get to the NEW Supplier action he can select on the form if the Supplier is a Person or a Company, and then something must be done to show the correct fields for. And back on the Create action, handle everything.
I have read many stackoverflow questions and watch Ryan Bates cast #197 and #394.
I'm a Rails enthusiastic, not a programmer.
If someone can point me out to the right direction, I would be thankful.
Regards,
David
This largely depends on the variety of fields you need, and how much data is shared. But if they are very different, I would actually have two separate divs or section on the page that a radio button toggles showing one & hiding the other with javascript. Can do this pretty easily with jquery at the bottom of the view, given it's a default in rails:
<input type="radio" name="supplier_type" value="person" />
<input type="radio" name="supplier_type" value="company" />
<script>
$('input[name="supplier_type"]').on('change', function () {
if ($(this).val() === "person") {
$('.person-form').show();
$('.company-form').hide();
}
else {
$('.person-form').hide();
$('.company-form').show();
}
});
</script>
Then inside each of those divs have an entirely separate form that post to different actions. If the data is different enough to require two forms, then it's worth having two different controllers for this.
Now if it's just a couple fields different, or an additional field for one or something. I would have the radio button same as above inside the form_for. Again attach some javascript to show or hide the values. In the controller, use a check against the radio button value to get the params you need:
supplier_params = params.slice :list, :of, :generic, :params
if params[:supplier_type] == "company"
supplier_params.merge! params.slice :company_name
elsif params[:supplier_type] == "person"
supplier_params.merge! params.slice :person_name
end
Supplier.new supplier_params
In my Rails app Users can have many People which in turn can (but don't have to) belong to Organisations.
In short, this:
Users --< People >-- Organisations
Now, it would be nice to be able to create new organisations from within a people view somehow. It tried this:
class Person < ActiveRecord::Base
attr_accessible :name, :organisation_attributes
belongs_to :user
belongs_to :organisation
accepts_nested_attributes_for :organisation
end
But it's not working because Organisation is not a child of Person.
Is there another way to realise this?
Thanks for any help.
I can see that Person is actually a child of Organisation and its possible to make nested form for parent model also. And you are already using accepts_nested_attributes_for.
Im assuming that you want to show a Organisation form for a already saved person. Then
In your PeopleController#show method build the organisation
#person.build_organisation
And in people/show.html.erb
form_for(#person) do |f|
f.fields_for(:organisation) do |fo|
# show the fields of organisation here.
end
end
It should work.
Update:
I tried something similar and it worked :) Ive made a gist including the snippets.
Please follow the link https://gist.github.com/3841507 to see it working.
Alright, I'm going to try to explain this as best as possible:
I have two models
employer.rb
class Employer < ActiveRecord::Base
has_many :listings
end
listing.rb
class Listing < ActiveRecord::Base
belongs_to :employer
end
Employers login through the employers_controller and listings are created through listings_controller
I'm having trouble getting the id from the employer table being inserted into the employer_id column in each individual created listing. I hope this makes sense. If anyone has any advice, it would be much appreciated. I have a feeling this is because I'm doing this outside of the employer_controller, but not sure.
Thanks!
1) If you are not dealing as nested resource then
When you render the new action of Listing controller, you know for which employer (#employer) you want to create the listing.
So render a hidden field for employer_id using a hidden_field or hidden_field_tag
hidden_field_tag 'employer_id', #employer.id()
2) If you are dealing as nested resource and your route looks something like
/employers/:employer_id/listings/new / (Get) && /employers/:employer_id/listings
Then in create action
#employer = Employer.find(params[:employer_id])
#employer.Listing.new(params[:listing]
I think you have the employer id in your session, since they need to login to create the listing. I won't use the param from the view, then its easy for one employer to create a listing as if it was created by another employer, just by changing the id value in your hidden field. Here's what is possibly a better approach:
#employer = Employer.find(current_user.id)
#employer.Listing.new(params[:listing]