Rails dynamic & modifiable form schemas - ruby-on-rails

I have a problem with forms. I'm developing an application that allows applicants to submit applications, and I want to make sure that users (people who receive those applications) could add/delete questions in their applications. How would I implement that?
My thought is to have a Application model and a ApplicationQuestion model that belongs_to Application. But I'm pretty lost beyond that.
UPDATE:
Another issue is confusing me. In my systems I could get Admins to add/delete ApplicationQuestions dynamically, and I have no problem implementing that. However, I want the Users to see the current set of ApplicationQuestions and answer them without being able to add/delete/edit questions. I'm now using a proxy model ApplicationQuestionAnswer which belongs_to Application and ApplciationQuestion. However I'm still having trouble with the views.

I'm actually more concerned about the views. How should I render the
forms to form-fillers?
Start with an Application form containing a stable amount of Questions (refer to Rails nested forms to implement it). The basic implementation could look like that:
<%= form_for #application do |f| %>
<%= f.fields_for :application_questions do |aq_form| %>
<%= aq_form.text_field :question %>
<%= aq_form.text_field :question %>
Dynamic adding and removing questions could be achieved by adding (and removing) HTML blocks produced by Rails helpers shown above:
<%= aq_form.text_field :question %>
You could dig into it's implementation by yourself (and write some javascript to orchestrate HTML blocks addition/removement) or use some gem with that functionality. One of those popular solutions is cocoon. It provides you with pretty links (link_to_add_association and link_to_remove_association), which being clicked perform the desired dynamic actions. You may be intrested in trying a cocoon demo application to get an idea of how to embed it into your project.

Yes you can keep the models as you are thinking. There will be a User model which would have two roles basically. One would be the teacher (just taking an example) who asks the questions and one would be student who will answer those questions. Now the teacher would be able to create application having different questions so two more models Application and ApplicationQuestion. The relations can be:
Application belongs_to User
ApplicationQuestion belongs to Application
Now the student will answer the questions which can be stored in answer table which would be another model ApplicationQuestionAnswer which would also belong to User and ApplicationQuestion. Now the questions can be of different type (numeric, string, date etc) so take care of that, they all can be stored in a single column by handling it at the code end and for this also have a question_type attribute in the ApplicationQuestion model.
Now the teacher can edit the application and delete the questions if they want or add new. Be sure to add dependent destroy so the answer would also be deleted when the question is deleted. Also suppose if the question can have choices then be sure to add one more model ApplicationQuestionChoice which would belong to ApplicationQuestion and its id will be saved as the answer of the student.
Update:
The ApplicationQuestionAnswer model will save each question's answer instead what you can do is that have two models. One would be ApplicationAnswer and another ApplicationQuestionAnswer. And the associations would be:
ApplicationAnswer belongs_to User
ApplicationAnswer belongs_to Application
ApplicationQuestionAnswer belongs_to ApplicationAnswer
Now in the view the form would be for creating/updating ApplicationAnswer and having nested forms for its associated ApplicationQuestionAnswer which you will display to the students. And this will save all the answers.
Also the same nested forms can be used with the teacher to add or remove questions. You can also use any gem for nested form too:
cocoon
nested_form
Hope this helps.

Related

how to continue after the nested model forms railscasts?

I followed the railscasts nested model form part 1, making some changes to have it work in rails 4. Basically, I created 3 models: Quiz, Question, and Answer, and they all belong_to the model intuitively above them. A form in the new action is used to create the quiz itself.
However, I'm at a bit of loss on how to proceed now. After creating the quiz, the show view looks like this:
done by iterating through #quiz.questions and #quiz.questions.answers and just displaying them on the page with their respective content attributes.
That's great for displaying just the questions and answers, but it doesn't accept user input at all. How do I make it so the user can use radio buttons to select an answer, and have it submit SOMEWHERE to save the results for grading and future reference for the user?
I've actually tried to create a form simply within the show action and have it save to another model but I got stuck extremely quickly. I'm finding it really difficult to both display the results AND accept user input for the displayed results. I also can't figure out a good way to save this data. Making another 3 models with the equivalent of Questions having something like a user_answer attribute seems difficult to implement and messy. I'm a beginner of the grandest caliber so any help would be great!
Nachime, your data model is good so far from what I can tell. Now you will want to link the answers to the users via many-to-many relationship. Note: this assumes that users will only take each quiz once.
Your next data model version will have a users_answers table containing user_id and answer_id. You can access the relative models using the has_many :through association so that each user has_many :answers, through: :users_answers.
The quiz will essentially just link the logged in user to the array of answers selected.

In a single form, linking two instances of two models with habtm

I am using Rails 3.
I have a Product model and a Group model (a group has_many users, through membership).
I would like to build the new.html.erb form for the product model, and at the end of the form, I would like the user to be able to choose members from which group(s) can have access to the product he wants to add.
So, my goal is to list the groups to which the user belongs to, adding a checkbox for each of them. Then, create the associations between the product inserted and the different groups the user selected when the form is submitted, but I really do not understand how to achieve this, as all the documentation I have read use the BUILD or CREATE method that defines a new instance of group, instead of an existing one.
Is it possible with a nested form, and a HABTM relationship between product and group ? Or should I use a nested form with a has_many_through association using new model product_group_relationship ? Or should I use something else than a nested form ?
I'm quite new in Rails and a little bit lost here, so if some experienced guy could guide me a little bit, it would be very much appreciated!
The form_for helper comes with a nice package of extra methods like: fields_for wich makes you able to add nested attributes for has_many_through relations.
I suggest reading these:
http://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for
And make sure you set your model validations accordingly

How to edit accepts_nested_attributes_for?

I have a Company model that has_many Address(es) and many Phone(s).
Address(es) belong_to Company as do Phone(s).
My problem is that I don't understand how to edit a Company's particular Adress and Phone.
In my edit action, I call up the specific record and assign it to an instance variable (i.e. #address = some scoped searched for the specific address I want), and then in my fields_for I references this child's attributes, ex:
<%= f.fields_for :addresses, #address do |address| %>
A) I'm not sure if this is the way to do it. The documentation on how to access a parent's specific child for editing is sparse.
B) While this works fine if the update succeeds, when it fails and I render :edit the view presents additional fields with the parent's current child (the one I specified in my edit action + another child -- seemingly the next record in line).
So basically, my form is extended with two children when the render :edit is called. Weird.
What's the deal with this? How do nested attributes work? Is there a better way to manage forms with multiple associated models?
Thanks.
It sounds like you are using the fields_for helper outside of its purpose here. From what you've described, you want to edit an address outside of its parents relationship. If that's the case you'll edit that address in its own form (and likely its own controller) using the form_for helper.
The fields_for would be used if you wanted to do any CRUD operations in the same form as the parent thereby leveraging the accepts_nested_attributes_for functionality.
Defiantly watch the screen casts that dmarucco posted to get a good and general understanding of nested forms, then check out the problem I had before here with nested forms (I too had a many to many relationship):
Rails 3.1+ Nested Forms Issue: Can't mass-assign protected attributes
I posted my solution at the bottom of that page.
I also used nested_form and simple_form gems for formatting my nested forms, so you may want to look into that
Hope this sets you in the right path!
These screencasts could you help much more than thousands words.
Railscast - Lesson 1
Railscast - Lesson 2

Mixing forms in Rails

In my app users can register information about a tournament. If the user is a paying customer, she can fill in additional info, otherwise the fields for the additional info are unavailable (visible but disabled).
I laid this out as two objects: Tournament and TournamentExtras where the former has_one :tournament_extras and the latter belongs_to :tournament. Tournament also accepts_nested_attributes_for :tournament_extras.
I would like this to show up as a single form. The fields in the two objects are related, meaning you can add a start date (to Tournament) but only paying customers can add an end date (to TournamentExtras) but since the two fields are logically realted, they should show up after eachother in the form.
How do I do this?
I tried opening the form_for and fields_for loops withing eachother (before adding any fields) hoping that I could add any field whereever I like. That didn't work; apparently you can't reference the form object within the fields loop(?).
form_form and fields_for should work with each other.
Somewhat of a skeleton for this is:
form_for(#tournament) do |f|
f.fields_for(#tournament.tournament_extra) do |g|
end
end

how to create reviews using polymorphic associations

I have three models that can all have a Review and each review must belong to a User. I am using polymorphic associations :as => :reviewable but I am not sure where I should put the logic for creating a review for each model. I would assume that the CRUD for each review should be handled by the reviews_controller (or nested attributes? in the other controllers?), but then how do I associate the review with each model ?
I couldn't find any examples of model/view/controller on google, maybe that would help a lot in clearing out things.
Thanks,
Cezar
The problem with handling the object within the reviewable objects' controllers is that you'll find you wind up repeating a lot of the same code in each of the controllers. Moreover, where do you put the code? Either you wind up with some seriously heavy action methods (by piggy backing on your 7 existing actions) or you start creating actions like
new_review, delete_review, etc
which is not RESTful and is a serious code smell begging for its own controller.
Therefore, for something like this I'd consider having a review controller and either adding parameters to the url or using hidden fields to indicate what object the review belongs to:
<%= f.hidden_field :reviewable_id, :value => #object.id %>
<%= f.hidden_field :reviewable_type, :value => #object.class %>
This is particularly useful if there is any other work that needs to be done on the review object (such as save the current user as the author, etc.), as it keeps all the logic that can't be pushed out to the model in one place. Just be sure to scope the associated model correctly and ensure it belongs to the user, otherwise users can tamper with the URL and add reviews to whatever they want (of course that applies anywhere you select an object from user submitted data).
However, if the review object is very light-weight and doesn't require any extra processing (ie just a simple assignment of the posted data to the object) then you might want to take a look at using Rails 2.3 and it's nested object support.
Since it's an update to the model, it's easier to go through the model's controller. Plus then there is no mistaking which model the review belongs to.
Take a look at what acts_as_commentable does. It might be easier to repurpose than to roll your own.
http://github.com/jackdempsey/acts_as_commentable/tree/master

Resources