I am developing a website which will host different tests on any subject.
I am using nested forms for referencing.
An exam has questions and a question has 4 options and every question has correct answers.
the models are like this:
class Exam < ActiveRecord::Base
has_many :questions
validates :name, presence: true
accepts_nested_attributes_for :questions,
reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
end
class Question < ActiveRecord::Base
belongs_to :exam
has_many :correct_answers
validates :content, presence: true
has_many :options
accepts_nested_attributes_for :options,
reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
accepts_nested_attributes_for :correct_answers, reject_if: proc {|attributes| attributes['content'].blank?},
allow_destroy: true
end
class Option < ActiveRecord::Base
belongs_to :question
end
Now i am not able to understand how to create a web form which can submit the results and can compare the selected choice with correct answer, then render the view with correct answer and selected answers.
Please help.
I guess you can use something simple like:
<%= form_for(#exam) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :question %>
<%= f.text_field :question%>
<%= f.submit Submit %>
FYI just read this article if you need any further help with your form
-> https://www.launchacademy.com/codecabulary/learn-rails/writing-forms
Related
I'm using Rails 6 + cocoon gem with vanilla js. I'm creating a website with quizzes, and quizzes, questions to them and answers to questions should be created on one page. Because of that i used double nested forms:
class Test < ApplicationRecord
belongs_to :author, class_name: 'Teacher'
belongs_to :article, optional: true
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, reject_if: :all_blank
end
class Question < ApplicationRecord
belongs_to :test
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, reject_if: :all_blank
validates :title, presence: true
end
class Answer < ApplicationRecord
belongs_to :question
validates :content, presence: true
validate :validate_max_answer_amount, on: :create
scope :correct, -> { where(correct: true) }
private
def validate_max_answer_amount
errors.add :base, :invalid_amount, message: 'Too many answers!' if question.answers.count >= 5
end
end
The problem lies precisely in the display of fields when they are added using cocoon. For example:
Can't post here images, because i have 1 rep, so check here please
Initial form - 1st screenshot
Form after adding answers - 2nd screenshot (expected that new fields would be lower than old one)
Form after adding questions - 3rd screenshot (expected that new fields would be lower than old one & that new fields would contain field for the first answer)
My View files:
tests/_form.html.slim:
=render 'shared/errors', object: #test
=form_with model: [:teacher, #test], local: true do |f|
=f.number_field :author_id, class: 'hidden'
=f.number_field :article_id, class: 'hidden'
.mb-3.add-questions
p
| Add questions:
.mb-3
=f.fields_for :questions do |q|
=render 'teacher/questions/question_fields', f: q
br
br
=link_to_add_association 'Add one more question', f, :questions, partial: 'teacher/questions/question_fields'
=f.submit 'Submit', class: 'btn btn-outline-success btn-lg mb-4'
questions/_question_fields.html.slim:
.mb-3.row
.col-sm-2.col-form-label
=f.label :title, 'Title'
.col-sm-10.col-form-label
=f.text_field :title, class: 'form-control'
=f.fields_for :answers do |a|
=render 'teacher/answers/answer_fields', f: a
=link_to_add_association 'Add one more answer', f, :answers, partial: 'teacher/answers/answer_fields'
answers/_answer_fields.html.slim:
.mb-1.row
.col-sm-1
.col-sm-2.col-form-label
=f.label :content, 'Enter content'
.col-sm-8.col-form-label
=f.text_field :content, class: 'form-control'
.col-sm-1.col-form-label
=f.check_box :correct, {class: 'form-check-input'}, true, false
I tried to remove =render 'teacher/answers/answer_fields' in questions/_question_fields.html.slim, but it didn't help with the problem with the questions. That is, new questions appeared anyway without an answer field.
I haven't figured out how to try to solve the problem with adding fields for answers (so that new fields appear below the old ones), so I hope for your help!
I have this problem. I need to validate the attributes of two models in the same form in Rails. One is the parent of the other.
The form is like this:
<%= semantic_form_for #professional do |pro| %>
<%= pro.inputs :id => "information" do %>
<%= pro.input :name, label: t("Artistic Name") %>
<%= pro.semantic_fields_for #user do |user| %>
<%= user.inputs :id => "register" do %>
<%= user.input :email, :placeholder=>"email#example.com" %>
<%= user.input :password, label: t('Password') %>
<%end%>
<% end %>
<% end %>
<% end %>
The models I am using are like this:
User:
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true
validates :email, :password, presence: true
end
Professionals:
class Professional < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy
accepts_nested_attributes_for :user
validates :date_birthday, :gender, :height, :name, :description, :Weight, :address, :languages,:services, :category, :phonenumber, :fullname, :hair_color, :age, :orientation, presence: true
end
So, what is the problem?
When I clicked in the submit button the professional attributes are marked but not the users attributes.
Like this:
The fields marked in red belongs to the professional model but the fields email and password belongs to the user model aren't marked in red when it should be because they are empty.
What can i do? I need the warning message for the user is attributes too
Thanks in advances.
We've achieved what you need before.
We had to use inverse_of so that the object was a singular piece of data (rather than multiple pieces as is the case by default):
#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true, inverse_of: :user
validates :email, :password, presence: true
end
#app/models/professional.rb
class Professional < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy, inverse_of: :role
accepts_nested_attributes_for :user
end
This will help.
You also need to make sure you're passing these objects correctly (I see so many people not doing this).
You need to tell Professional to validate the associated User:
class Professional < ActiveRecord::Base
...
validates_associated :user
I have 3 models
User
Business (acts_as_commentable using acts_as_commentable gem)
Comment (belongs to user)
On the Business show page I display all the comments associated with that business:
Name:<%= #business.name %>
<%= render #business.comments %>
comments partial
Comment: <%= comment.comment %><br >
By: <%= User.find(comment.user_id).name %>
Is there a better way to display the name of the user instead of using User.find?
Here are my models
User
class User < ActiveRecord::Base
attr_accessible :email, :name
end
Business
class Business < ActiveRecord::Base
attr_accessible :name, :category
has_reputation :votes, source: :user, aggregated_by: :sum
acts_as_commentable
end
Comment
class Comment < ActiveRecord::Base
include ActsAsCommentable::Comment
attr_accessible :comment, :user_id
belongs_to :commentable, :polymorphic => true
default_scope :order => 'created_at ASC'
belongs_to :user
validates :user_id, presence: true
end
I believe you can just use this:
<%= comment.user.name %>
Rails will handle loading for you.
Each comment belongs to a user. So, you just have to get the user this way
comment.user.name
I think the best way is:
<%= comment.user.try(:name) %>
I see you have validates :user_id, presence: true to have user. But if the use has deleted, comment.user.name will put the error.
Or you can use:
<%= comment.user.blank? ? "Visitor" : comment.user.name %>
So I have the following models:
Image:
class Image < ActiveRecord::Base
has_many :product_images
has_many :products, :through => :product_images
attr_accessible :asset, :name, :description, :product_ids, :file_content_type, :is_boolean
accepts_nested_attributes_for :product_images
has_attached_file :asset
end
ProductImage:
class ProductImage < ActiveRecord::Base
belongs_to :product
belongs_to :image
attr_accessible :is_thumbnail
end
and Product:
class Product < ActiveRecord::Base
has_many :images, :through => :product_images
has_many :product_images
attr_accessible :name, :description, :thumbnail, :searchTerms, :group_ids, :upload_file_ids
end
Now what I would like to do on the images form is display a checkbox for all the products and then another checkbox for the is_thumbnail attribute
I have had a look into using simple_fields_for but this will only display if the product has already been added. Is there a way to do this?
<%= f.simple_fields_for(:product_images) do |builder| %>
<%= builder.input :is_thumbnail %>
<%= builder.association :products, include_blank: false %>
<% end %>
I'm not very familiar with simple_fields however building form inputs base on an instance will only allow you to "represent" that instance.
This means that you could print all already associated products using
builder.association :products
but if you want to print all products in your database you will need to fetch them, loop and display them in your form.
I have two models, Artist and User that are connected through a third model, ArtistMembership.
From the edit/new Artist form, I want to be able to edit the role of any User in an existing ArtistMembership relationship for that Artist, delete ArtistMemberships, and add new AtistMembership relationships, which would include a User and :role.
Here's my Artist model:
class Artist < ActiveRecord::Base
has_many :artist_memberships, foreign_key: "artist_id", dependent: :destroy
attr_accessible :bio, :created_at, :email, :location, :name, :updated_at, :website, :pic
accepts_nested_attributes_for :artist_memberships, :allow_destroy => :true
...
end
Here's my User model:
class User < ActiveRecord::Base
...
has_many :artist_memberships, foreign_key: "user_id"
...
end
Here's my ArtistMembership model:
class ArtistMembership < ActiveRecord::Base
belongs_to :artist, class_name: "Artist"
belongs_to :user, class_name: "User"
attr_accessible :artist_id, :created_at, :role, :user_id
end
If I have a _form.hml.erb too, for editing Artists that starts:
<%= form_for #artist do |artist_form| %>
<div class="field">
<%= artist_form.label :name %>
<%= artist_form.text_field :name %>
</div>
..
<div class="actions">
<%= artist_form.submit %>
</div>
<% end %>
how can I create the related ArtistMembership forms for the aforementioned functionality?
May be this is helpful for you, see this field_for
you can use accepts_nested_attributes_for(*attr_names)
Maybe you are looking for this method.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Refer to the "One-to-many" section.
But if I were you, I would rather use the "Nested Resource" technic.
http://guides.rubyonrails.org/routing.html#nested-resources