Rails: Dynamically created forms - how to accept answers for questions? - ruby-on-rails

I have looked on the internet and stared at my screen for hours now and hope that you guys can help me out and can stop me from thinking in circles :) I've already found http://railscasts.com/episodes/196-nested-model-form-part-1 and http://railscasts.com/episodes/197-nested-model-form-part-2 but still can't get my mind around it...
Context
I'm trying to develop a CMS where users can create dynamic forms, with their own specific questions, question help text and possible answers (in case of radio buttons/checkboxes)
I am able to create the questions and the forms and to show the question in the viewer, my next step is to allow other users to answer the questions, but can't figure out how to do that.
What I have so far:
Form model:
has_many :custom_questions
has_many :custom_themes
has_many :form_submissions
has_many :answers
accepts_nested_attributes_for :answers
Question model
belongs_to :custom_form
belongs_to :custom_theme
has_many :possible_answers
accepts_nested_attributes_for :possible_answers
has_many :answers
accepts_nested_attributes_for :answers
Answer model
belongs_to :custom_questions
belongs_to :possible_answers
belongs_to :form_submissions
and the viewer which I use to load the questions and input fields:
<div class='content custom_forms clearfix'>
<%= form_for #customForm do |f| %>
<ul>
<%= #customForm.custom_themes.order(:order).each do |theme| %>
<div class='align_element'>
<section class='form_theme_title clearfix'><%= raw theme.theme_title %></section>
<section class="form_theme_description clearfix"><%= raw theme.theme_description.linkify %></section>
</div>
<ul class='selfce-reviews-table clearfix'>
<%= render "reviews/tabHeader" %>
<li class='row clearfix'>
<ul>
<li class="clearfix">
<% theme.custom_questions.order(:order).each do |question| %>
<li class='column selfc'>
</li>
<li class='column rev'>
<div class='align_element'>
<section class='form_question clearfix'>
<%= raw question.question %>
</section>
<section class="form_description clearfix">
<%= raw question.description.linkify %>
</section>
<%= f.fields_for question.answers.build do |builder| %>
<%= builder.hidden_field :custom_question_id, value: question.id %>
<% if question.q_type == "textfield" or question.q_type.nil? %>
<%= builder.text_field :answer, class:'reviews-inputBox clearfix' %>
<% elsif question.q_type == "textarea" %>
<%= builder.text_area :answer, class:'reviews-inputTextarea clearfix tinymce' %>
<%= tinymce %>
<% elsif question.q_type == "checkbox" %>
<% elsif question.q_type == "radio-button" %>
<% end %>
<% end %>
</div>
</li>
<% end %>
</li>
</ul>
<%= f.submit %>
</li>
<% end %>
</ul>
<% end %>
</div>
What I want is to store each answer in the table "answers" in the fields:
- question_id which refers to the unique id of the question
- answer - the value of the input field
As you can see I use #customForm which is the generated form by the administrator. I assume I use it here in the wrong way, because I don't want to update the form but only the answers... so instead it should be something like form_for :answers but that doesnt seem to work..
So my first question:
The way I see it every answer is unique and should therefore be seen as a unique form, hence my nested forms.. However if I use my code right now every input field has the same id: "custom_form_answer_answer". Is there a way I don't have to use nested forms to load the input fields for each question, e.g. by giving each answer a unique id based on the question_id?
I can't hardcode the inputfield name since this can change any time the user creates a new field..
My second question
If there is a way to do that.. how can I save the answers then..
Please let me know if you need any addition information.. and please keep in mind I'm fairly new to rails... so still learning!
Thanks! =-)

Related

editing multiple child records while accessing values of other attributes of said record

For class
class Product
has_many :productunits
accepts_nested_attributes_for :productunits
class Productunit
belongs_to :product
belongs_to :unit
validates :product_id, presence: true
validates :unit_id, presence: true
the following form is meant only to update existing records (of what is effectively a join table), while formatting the fields in columns (one column per child) and effecting some view logic on whether the field should be shown or not.
<div class='grid-x grid-margin-x'>
<%= f.fields_for :productunits do |price_fields| %>
<div class='cell small-2 text-right'>
<h4><%# productunit.unit.name %> </h4>
<%# if productunit.unit.capacity == 2 %
2 <%= label %> <%= price_fields.number_field :price2 %>
<%# end %>
</div>
<% end %>
</div>
However a number problems are arising:
I cannot invoke the value of an attribute of record being edited (say productunit.unit.capacity)
The natural break in child records is not accessible to html tags for formatting (<div class='cell [...]). Worse, rails is throwing the child record id outside the div definition </div>
<input type="hidden" value="3" name="product[productunits_attributes][1][id]" id="product_productunits_attributes_1_id" />
<div class='cell small-2 text-right'>
submitting the form returns an error Productunits unit can't be blankwhich would be fair for a new record, but is definitely not expected when editing an existing one.
Unfortunately, the rails guide is thin in this regard.
I cannot invoke the value of an attribute of record being edited
You can get the object wrapped by a form builder or input builder though the object method:
<div class='grid-x grid-margin-x'>
<%= f.fields_for :productunits do |price_fields| %>
<div class='cell small-2 text-right'>
<h4><%= price_fields.object.unit.name %> </h4>
<% if price_fields.object.unit.capacity == 2 %
2 <%= price_fields.label :price2 %> <%= price_fields.number_field :price2 %>
<% end %>
</div>
<% end %>
</div>
2 The natural break in child records is not accessible to html tags
for formatting...
fields_for just iterates through the child records. Its just a loop. I'm guessing you just have broken html like a stray </div> tag or whatever you're doing with <%= label %>.
submitting the form returns an error Productunits unit can't be blankwhich would be fair for a new record, but is definitely not expected when editing an existing one.
You're not passing a id for the unit. Rails does not do this automatically. Either use a hidden input or the collection helpers.
<div class='grid-x grid-margin-x'>
<%= f.fields_for :productunits do |price_fields| %>
<div class='cell small-2 text-right'>
<h4><%= price_fields.object.unit.name %> </h4>
<% if price_fields.object.unit.capacity == 2 %
2 <%= price_fields.label :price2 %> <%= price_fields.number_field :price2 %>
<% end %>
<%= price_fields.collection_select(:unit_id, Unit.all, :id, :name) %>
# or
<%= price_fields.hidden_field(:unit_id) %>
</div>
<% end %>
</div>
On a side note you should name your model ProductUnit, your table product_units and use product_unit everywhere else. See the Ruby Style Guide.

Make shuffle order persistent across loops (Ruby on Rails)

I need to access the same random shuffling across two different loops on the same ERB page.
Context:
I have questions which have five choices of which one is TRUE for choices.is_correct.
My current ERB (below) successfully displays:
1) Grouped by usage
2) All available questions (shuffled)
3) And all five choices (also shuffled)
What I'd like to add is a separate loop (directly after in the same ERB), which gives:
1) Same grouping by usage
2) Same order of available questions (eg, same shuffle order)
3) The correct answer choice (eg, answer "B" = referencing the same shuffling)
Assigning the question or choice shuffling globally would not work, as I need it to be randomized on each page load.
Current ERB (currently shuffles each loop separately)
<%= #exam.name %>
<br />
<% alpha_numbers = ("A".."Z").to_a %>
<% #book_questions_by_usage.each do |usage, question| %>
<h4><%= usage if usage %></h4>
<% question.shuffle.each_with_index do |question, i| %>
<%= i+1 %>: <%= question.name %>
<ol type="A">
<% question.choices.shuffle.each_with_index do |choice, index| %>
<% choice.alpha_order = alpha_numbers[index] %>
<li><%= choice.name %></li>
<% end %><br />
</ol>
<% end %>
<% end %>
<% #book_questions_by_usage.sort.each do |usage, question| %>
<h4><%= usage if usage %></h4>
<% question.shuffle.each_with_index do |question, i| %>
<%= i+1 %>: <%= question.name %>
<ol type="A">
<% question.choices.select { |choice| choice.correct }.shuffle.each_with_index do |choice, index| %>
<% choice.alpha_order = alpha_numbers[index] %>
Correct Answer: <b><%= choice.alpha_order %>. <%= choice.name %></b>
<% end %><br />
</ol>
<% end %>
<% end %>
question.rb
class Question < ApplicationRecord
before_validation :assign_questionable
belongs_to :questionable, polymorphic: true
has_many :choices, :dependent => :destroy
accepts_nested_attributes_for :choices, allow_destroy: true
choice.rb
class Choice < ApplicationRecord
belongs_to :question
I've spent hours looking into possible solutions with no success so far. Any help is much appreciated!
How about you don't shuffle in the view, but in the controller. Save the shuffled array in an instance method and then use it in the view where you need it.

Trying to collect a list of ids from checkboxes to delete from my database

I'm creating an app (personal project) that'll help us schedule and record Nerf tournaments for a group I hang out with. I have tournament and player models. A tournament can have multiple players.
I want to be able to check multiple players and choose to delete them from the tournament. The thing is though is that all of my players are rendered in a nested partial. And my tournament partial has a form already inside of it.
Here is _tournament.html.erb:
<section class="panel" id="<%= dom_id(tournament) %>">
<h1 class="heading">
<%= tournament.name %>
</h1>
<ul>
<%= render tournament.players %>
</ul>
<section class="add_players">
<%= form_for [tournament, Player.new] do |f| %>
<div class="form-group">
<%= f.text_field :name %>
</div>
<div class="form-group">
<%= f.text_field :team %>
</div>
<%= f.submit "Add Player", class="button blue" %>
<% end %>
</section>
<section class="delete_all">
<button class="button red" type="button">Delete Players</button>
</section>
</section>
and here is _player.html.erb:
<li id="<%= dom_id(player) %>">
<div class="player">
<%= check_box_tag "player_ids[]", player.id %>
<span class="name"><%= player.name %></span> |
<span class="team"><%= player.team %></span>
</div>
</li>
I'm familiar with Railscast #52 where he does a simpler example of this, but I can't figure out how to get all of those checked checkboxes in the tournament partial and use those ID's to delete those players from the tournament.
I've tried wrapping the _tournament.html.erb partial inside of a form_tag but it breaks some styling (and HTML doesn't really allow that as a standard.)
Any guidance or help would be great!
What you are doing is creating a form that posts to /tournaments/:tournament_id/players which makes sense if you are assigning the players one by one or creating a single player.
It does not make sense at all if you are assigning multiple players to a tournament. Because you are actually changing the parent resource.
In that case you should be sending a POST request to /tournaments (to create a tournament) or a PATCH request to /tournaments/:id (to modify an existing record).
<%= form_for tournament do |f| %>
<div class="form-group">
<%= f.label :player_ids, "Assign players" %>
<%= f.collection_check_boxes :player_ids, Player.all, :id, :name %>
</div>
<%= f.submit %>
<% end %>
class TournamentsController < ApplicationController
# ...
private
def tournament_params
params.require(:tournament)
.permit(:foo, :bar, player_ids: [])
end
end
If you want to be able to create multiple player records in a single request you should use nested attributes and fields_for.
To unassign all the players you can do a PATCH request to /tournaments/:id
with an empty array as the value for tournaments[:players_ids]. You can do this with javascript by creating a handler that unchecks all the checkboxes and submits the form when the user clicks the button (or confirms it).
Or you could create a custom DELETE /tournaments/:tournament_id/players route.
resources :tournaments do
resources :players
delete :players, on: :collection, action: :delete_all_players
end

Rails: how to count number of users?

here is my models.
User
unit_id
Unit
block_id
Block
postalcode_id
Postalcode
neighbourhood_id
Neighbourhood
name
the relations is for all is top belongs to bottom
this is my current index.html.erb file, i wish to output the number of user in each neighbourhood.
<% provide(:title, 'Neighbourhoods') %>
<ul class="thumbnails">
<% #neighbourhoods.each do |neighbourhood| %>
<li class="span3">
<div class="thumbnail">
<div style="position:relative;">
<%= link_to "Join", '#', class: "btn-join" %>
<%= image_tag(neighbourhood.name+".jpg", alt: neighbourhood.name) %>
</div>
<h2 style="margin-bottom:0px"><%= neighbourhood.name.titleize %></h2>
<% neighbourhood.postalcodes.each do |postalcode| %>
<%= postalcode.blocks.map(&:block).join(", ") %>
<% end %>
<br>
<%= neighbourhood.streetname.titleize %>
</div>
</li>
<% end %>
</ul>
Thanks in advance.
Assuming a Neighborhood has_many Users:
<%= neighbourhood.users.size %>
Note that counting is a relatively slow option, so you can optionally cache the number of users for speed using counter_cache:
class User < ActiveRecord::Base
belongs_to :neighborhood, :counter_cache => true
end
Then in a migration:
add_column :neighborhoods, :users_count, :integer, :default => 0
Seems like an awfully deeply nested set of associations. You may want to take a second look at your models and see if you can 'trim them down' a little. Maybe something like just have a User and Unit model, then add block, postal code and neighbourhood to Unit where you could do Unit.block, and Unit.postal_code...ect.
That being said with your current configuration (assuming correct associations of has_many/belongs_to) you should be able to do something like:
Neighbourhood.postal_code.block.unit.users.count
Good luck!

Associations not working in html.erb

<ol class="noDots">
<% # #screening.cinema.each do |screening| %>
<li>
<h3><%= screening.cinema.name %></h3>
</li>
<% #end %>
</ol>
Hi everyone,
There is an association between cinema and film through screening. Film model is separate and cinema is separate. Screening combines them together. In the cinema model, everything seems to work properly <%= screening.film.title %> works perfectly and displaying them in a loop works.
I want to create a dropdown of cinema.name with the link and it takes you there. The association has to exists as some movies in different cinemas.
Is that possible as the code above doesnt work for me.
Thanks in advance
<h3><%= screening.cinema.name %></h3>
This line should read...
<h3><%= screening.name %></h3>
And you could have this dropdown box in a form with a Submit button next to it to take you to that page...
Sounds like you are getting a lot "nil object" errors. Double check your controller to see what variables you are defining there that can be accessed in the views.
Eg, if you are setting #film, then you can traverse the associations with something like:
<% #film.screenings.each do |screening| %>
<li>
<h3><%= screening.cinema.name %></h3>
</li>
<% end %>
You should be able to alphabetize by cinema name as well, if you eager-load them when you grab the list of screenings:
<% #film.screenings.includes(:cinema).order("cinema.name ASC").each do |screening| %>
<li>
<h3><%= screening.cinema.name %></h3>
</li>
<% end %>
Hope that helps!
From what I see screen has_many :cinemas( not cinema has_many :screenings)
so
<% #screening.cinema.each do |cinema| %>
<li>
<h3><%= cinema.name %></h3>
</li>
<% end %>
please show the screening model and the cinema mode, but based on the gist..
Assuming
class Screening
belongs_to :film
belongs_to :cinema.
.....
end
class Film
has_many :screenings
has_many :cinemas, :through => :screenings
end
class Cinema
has_many :screenings,
has_many :films, :through => screenings
end
I think what you want is something along the lines of the following.
<ol class="noDots">
<% # #screenings.each do |screening| %>
<li>
<h3><%= screening.cinema.name %></h3>
</li>
<% #end %>
</ol>
Assuming that you set #screenings to subset of screenings you want in the controller..
This should work as it worked on your single screening in the comments.
In the controller
#screening = Screening.find(some_id)
In the view
<% #screening.cinema.each do |s| %>
<li>
<h3><%= s.cinema.name %></h3>
</li>
<% end %>

Resources