Select hidden and label from enum - ruby-on-rails

project.rb
class Project < ActiveRecord::Base
has_many :details, dependent: :destroy
accepts_nested_attributes_for :details, allow_destroy: true
end
details.rb
class Details < ActiveRecord::Base
belongs_to :project
enum question: {
0: "Question 1...",
1: "Question 2..."
}
end
details table
create_table "details", force: :cascade do |t|
t.integer "project_id"
t.integer "question"
t.string "answer"
end
project form
= form_for #project do |f|
...
%h3 Questions
= f.fields_for :details do |d|
.nested-fields
.field
= d.label (question value here)
= d.hidden_field (question ID here)
= d.text_field :answer
%br/
...
.actions
= f.submit "Submit"
Basically my project has a details table that is suppose to store a collection of 5 questions. Those questions are static and will always be the same. What I thought as a solution was to make and enum, and store in the details table the ID of the question and a string with the answer. But now I'm stuck with the form and I would like some help on how can make a form to create and edit the project details. On the form code you can find exactly what I'm trying to do in pseudo-code. I would also be open to a different implementation solution. Thanks!

You use ActiveRecord::Enum in a wrong way. It is meant to map values to integers:
enum question: {question1: 1, question2: 2},
while you're using it to map integers to values. I'd suggest that you create a simple accessor method:
def questions(index)
["Question1", "Question2"][index]
end
So that you can pick a question like that:
Detail.questions(n)
By the way, if you use Detail just for holding theses questions, get rid of it and put the above method in Project.

Related

Trouble establishing a has_and_belongs_to_many relationship in Rails

I have tried every possible suggestion I could find on here to make this work but still can't get it to happen.
I have two models: districts and former_offices -- a district can have many former offices and a former office has a district.
Districts:
class District < ApplicationRecord
has_and_belongs_to_many :former_office
end
Former Office:
class FormerOffice < ApplicationRecord
has_and_belongs_to_many :districts
end
Join Model:
class DistrictFormerOffice < ApplicationRecord
belongs_to :district
belongs_to :former_office
end
Here is my form setup for creating a new former office:
<%= bootstrap_form_for(#former_office, label_errors: true) do |f| %>
<%= f.select(:district_ids, District.all.collect { |v| ["#{v.jurisdiction.name} - #{v.name} (District #{v.district}) #{v.term_expires}", v.id ] }, { :include_blank => true}) %></div>
<% end %>
Former Offices controller:
def former_office_params
params.require(:former_office).permit(district_ids: [])
end
Migration:
class CreateJoinTableDistrictFormerOffices < ActiveRecord::Migration[5.2]
def change
create_table :districts_former_offices, id: false do |t|
t.bigint :district_id
t.bigint :former_office_id
end
add_index :districts_former_offices, :district_id
add_index :districts_former_offices, :former_office_id
end
end
I am able to create the Former Office without any errors. All the other fields populate just find, except for "districts." When I pull up the object in the console and type former_office.districts, it comes up as "nil." So it appears either data isn't being added to the database, or is added in the wrong manner.
In the views, if I set it to display #former_office.districts, it just shows up blank.
Let me know if you need further information from my end. I sense this is an easy fix...but just can't figure it out.
I don't think you can add "district_ids" directly into your FormerOffice model. Instead you need to load all the districts from the district model, like #districts = District.find(former_office[:district_ids)), and then do something like #former_office.districts = #districts

How to catch ids getting created and compare their attributes in rails active record

I have a Question model and a PossibleAnswer model the tables are as follows.
possible_answers
create_table "possible_answers", force: :cascade do |t|
t.integer "question_id"
t.string "title"
end
questions
create_table "questions", force: :cascade do |t|
t.string "title"
t.string "right_answer"
end
The association is (you could have guessed already but anyway)
Question.rb
class Question < ActiveRecord::Base
has_many :possible_answers
end
PossibleAnswer.rb
class PossibleAnswer < ActiveRecord::Base
belongs_to :question
end
Now I have a form where all the questions are posted with their respective choices. I have a controller to submit the answers by selecting the choices.
class RepliesController < ApplicationController
def create
#quiz = Quiz.find(params[:quiz_id])
#reply = #quiz.replies.build reply_params
if #reply.save
redirect_to #quiz, notice: "Thank you for taking the quiz"
end
end
def reply_params
params.require(:reply).permit({ answers_attributes: [ :value, :question_id, :possible_answer_id ] })
end
end
Now this create method is working fine. Once the user submits the quiz, the following data is created.
{"answers_attributes"=>{"0"=>{"possible_answer_id"=>"10", "question_id"=>"6"}}, "commit"=>"Finish quiz", "quiz_id"=>"1"}
Here the possible_answer_id is the option which user selected and the possible answer belongs to the question_id.
My question is, how can I compare the title from this possible_answer_id to the right_answer of the question_id.
I tried using find params and passing the id but didnt work.
Can anybody please help me here. I have a come a long way building this app and stuck here now.
Have you thought about adding a :correct, :boolean, default: :false to your possible_answers table. That way when the user selects the answer you're able to find it and see if it's correct.
Having the answer string in both question and possible_answers isn't the most efficient solution.
Alternatively (If you want to keep the answer in the questions table) you could change right_answer to possible_answer_id and have a has_one :possible_answer, as: :right_answer. So you can do:
question.possible_answers # returns list
question.right_answer # returns just the single record of the correct answer

Select many box for HABTM

I have two models; question and category which have a HABTM association between them. Now I want to have a form where I can edit the questions categories, however I don't know how. I started with this but I am lost, I am unsure on what to name the "name" attributes etc and how it is automatically edited/created with the question, how do I set this up?
<%= f.fields_for :categories do |categories_form| %>
<%= categories_form.select "category_ids", Category.all.collect { |c| [c.description, c.id] }, {}, {:multiple => true, :size => 9} %>
<% end %>
I managed to set up question(has_many) --> answer with fields_for and accepts_nested_attributes_for, but not this.
You should take a look at the following screencasts by Ryan Bates Nested Model Form Part 1 and Nested Model Form Part 2.
Migrations
You need to create the migrations for the tables
You need to create the migration for the middle table of the association
+ the middle table name that is created by the association is :categories_questions
or :questions_categories, in the second case you must define the name in models as shown in the link
Do I need to manually create a migration for a HABTM join table?
class CreateCategoriesQuestions < ActiveRecord::Migration
def self.up
create_table :categories_questions, :id => false do |t|
t.references :category
t.references :question
end
add_index :categories_questions, [:category_id, :question_id]
add_index :categories_questions, [:question_id, :category_id]
end
def self.down
drop_table :categories_questions
end
end
Question Model
class Question < ActiveRecord::Base
has_and_belongs_to_many :categories
end
Category Model
class Category < ActiveRecord::Base
has_and_belongs_to_many :questions
end
Controller Stuf
questions_controller.rb
def new
#question = Question.new
#question.categories.build #Build a categories_questions so as to use fields_for
end
Form Stuff
= f.fields_for :categories do |categories_fields|
= categories_fields.text_field :name
= categories_fields.text_field :description
At this point i must tell you ( i am new in ruby & rails ) that to create a new object here you can use jquery to append a html block name properly, or create helpers (that use javascript in the end) to add a new object and on save, save the association.
In the next link someone demonstrated the exact way .
http://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for#512-Setting-child-index-while-using-nested-attributes-mass-assignment

Ruby on Rails: passing in a variable to an active record query

This question relates to a RoR quiz app. I am looking to display the results of the quiz, showing both the correct answer as well as the user's answer.
Therefore, in my view, I need to loop through each question and show the question answer, as well as the user's answer. However, I am struggling trying to figure out how to correctly query the user's answer.
To query the user_answer, I need the response_set where the user_id = current_user.id and I need to pass in the question_id as it loops through the each loop. However, I'm stuck on how to accomplish this.
What do I need to do to show the user_answer in the view alongside the correct_answer?
I have 3 models:
Response_set
belongs_to :user
has_many :responses
Reponse
belongs_to :response_set
belongs_to :question
Question
has_many :responses
Table fields:
create_table :response_sets do |t|
t.integer :user_id
create_table :responses do |t|
t.integer :response_set_id
t.integer :question_id
t.integer :user_answer
create_table :questions do |t|
t.integer :correct_answer
Controller
#questions = Question.all
#user = current_user.id
View (just looping through the questions and not displaying the user's answer)
<% #questions.each do |question| %>
<%= question.correct_answer %>
<% end %>
My mentor ended up solving this one for me. Here is the solution that he presented:
"I think a better approach here would be get the responses from the
response set and loop over that instead of looping over the
questions."
Controller:
#response_set = Response_set.where("user_id = ?", #user).includes({:responses => :question}).last
View:
<% #response_set.responses.each do |response| %>
<%= response.question.correct_answer %>
<%= response.user_answer %>
<% end %>
Add user_id in responses table, this way you don't have to query response_set table.
After this you can do something like this inside the loop
question.responses.where(:user_id => current_user.id).first.user_answer

Polymorphic Associations in Rails for different 'author' models

How would a Polymorphic Association (here: Comments) be itself associated with different types of Authors?
Starting from …
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => :true
end
… I'd need to have one author being from model Hosts, ID 5 and another one from Users, 2.
How could path helpers look like…
<%= link_to comment.author.name, user_path(comment.author) %>
… when "user_path" or "host_path" are dynamic, depending on the author model?
EDIT***
There are Events, Places etc. that can have comments like so:
has_many :comments, :as => :commentable
To the polymorphic Comment model i would like to add IDs and Types to refer to Authors of comments:
create_table "comments", :force => true do |t|
t.text "content"
t.integer "commentable_id"
t.string "commentable_type"
t.integer "author_id"
t.string "author_type"
end
An Events page displays comments, and clicking on an author name should take me either to User(5) oder AnotherModel(2), depending on who wrote the comment.
I'd like to know how everybody handles this kind of situation. Should I think about adding a second polymorphic "middle layer", such as "profile", that could hold the subclasses "User", "Host" and so forth?
EDIT 2
Having only one User model would make life easier here obviously, but that cannot be done for other reasons. And in general i'm interested how this could be organized well.
Simply putting
<%= link_to comment.author.name, comment.author %>
should do the trick. If you want more flexibility, I would suggest
link_to ..., action_in_host_path(comment.author) if comment.author.kind_of? Host
This is what I've used in the past (in a view helper), but it uses an eval:
def model_path(model, options = {})
{:format => nil}.merge(options)
format = (options[:format].nil? ? 'nil' : "'#{options[:format].to_s}'")
eval("#{model.class.to_s.downcase}_path(#{model.id}, :format => #{format})")
end
Use like this:
<%= link_to comment.author.name, model_path(comment.author) %>
Would polymorphic_url help?
<%= link_to comment.author.name, polymorphic_url(comment.commentable)
%>

Resources