I have a Forum that has_many :forum_threads and has_many :forum_posts, through: :forum_threads. So basically my Forums have their own Forum Threads that are related to that particular Forum topic. I've added Searchkick to handle the search form. Searchkick is working for my Forum table but not for my ForumThread table.
There is no error, it just renders out all of the forum threads instead of rendering the query that the form was given.
Searchkick GitHub
Here are my files:
forum.rb
class Forum < ActiveRecord::Base
accepts_nested_attributes_for :forum_threads
has_many :forum_posts, through: :forum_threads
accepts_nested_attributes_for :forum_posts
searchkick text_start: [:title], suggest: [:title], autocomplete: [:title]
def search_data
{
title: title
}
end
end
forums_controller.rb
class ForumsController < ApplicationController
def index
query = params[:q] || "*"
#forums = Forum.search(query, suggest: true, fields: [:title],
boost_where: {specific: :exact})
end
end
views/forums/index.html.erb
<%= form_tag forums_path, method: :get do |f| %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forums.suggestions.any? %>
<p class="lead">
<em>Did you mean: <strong><%= #forums.suggestions.first %></strong>?</em>
</p>
<% end %>
forum_thread.rb
class ForumThread < ActiveRecord::Base
belongs_to :user, counter_cache: true
belongs_to :forum, counter_cache: true, touch: true
has_many :forum_posts, dependent: :destroy
accepts_nested_attributes_for :forum_posts
validates :subject, presence: true
validates_associated :forum_posts
searchkick text_start: [:subject], suggest: [:subject], autocomplete: [:subject]
def search_data
{
subject: subject,
description: description
}
end
end
forum_threads_controller.rb
class ForumsController < ApplicationController
def index
query = params[:q].presence || "*"
#forum_threads = #forum.forum_threads.search(query, suggest: true, fields: [:subject, :description])
end
end
views/forum_threads/index.html.erb
<%= form_tag forum_forum_threads_path(<!-- something here? -->), method: :get do %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forum_threads.suggestions.any? %>
<p class="lead"><em>Did you mean: <%= #forum_threads.suggestions.first %>?</em></p>
<% end %>
routes.rb
Rails.application.routes.draw do
resources :forums do
resources :forum_threads do
resources :forum_posts do
member do
put 'like', to: 'forum_posts#upvote'
put 'dislike', to: 'forum_posts#downvote'
end
end
end
end
end
I just made a variable for suggestions to use in the view.
forum_threads_controller.rb
def index
query = params[:q].presence || "*"
#forum_threads = ForumThread.search(query,
where: { forum_id: #forum.id },
fields: [:subject, :description],
boost_where: {specific: :exact}, suggest: true, highlight: true)
#forum_threads_suggestions = []
if #forum_threads.empty? && #forum_threads.suggestions.any?
#forum_threads_suggestions = ForumThread.search(#forum_threads.suggestions.first, fields: [:subject], suggest: true,
boost_where: {specific: :exact}, highlight: true)
end
end
index.html.erb
<%= form_tag forum_forum_threads_path, method: :get do %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forum_threads.suggestions.any? %>
<p class="lead">
<em>
Did you mean: <strong><%= #forum_threads.suggestions.first %></strong>?
</em>
</p>
<% end %>
</div>
<!-- END SEARCH FORM -->
<!-- SHOW RESULTS AND SUGGESTIONS -->
<p class="light-grey"><em>
<%= pluralize #forum_threads.results.size, 'match' if params[:q].present? %>
<%= pluralize #forum_threads.suggestions.size, 'suggestion' if #forum_threads.suggestions.any? %>
</em></p>
<!-- END RESULTS AND SUGGESTIONS -->
<!-- SHOW FORUM THREADS -->
<% (#forum_threads.presence || #forum_threads_suggestions).each do |forum_thread| %>
I wrote an or statement to either show all forum_threads or suggestions.
forum_thread.rb)
searchkick fields: [:subject], suggest: ['subject'], highlight: [:subject]
def search_data
{
forum_id: forum.id,
forum_thread: #forum_thread,
subject: subject
}
end
I did the same thing for the forum model. I'm not sure if this is the best way to go about doing this so if someone else has something then please feel free to contribute.
Related
I am getting ready to give up on this... I 've searched every question on this, done multiple tests and I can't figure it out.
I am trying to create new records of a model (absences) through nested attributes (classroom -> students).
Here is a hash that I manually created and gets saved when I call
# hash: {"classroom"=>{"rank"=>"aaa", "grade_id"=>"", "students_attributes"=>{"0"=>{"last_name"=>"aaa", "first_name"=>"aaa", "absences_attributes"=>{"0"=>{"class_time"=>"1", "status"=>"valid"}}}}}, "id"=>"26"}
#classroom = Classroom.find(params["id"])
#classroom.update(params["classroom"])
This gives me:
(0.5ms) begin transaction
SQL (1.3ms) UPDATE "classrooms" SET "rank" = ?, "updated_at" = ? WHERE "classrooms"."id" = ? [["rank", "aaa"], ["updated_at", "2016-08-10 21:09:17.883875"], ["id", 26]]
SQL (0.2ms) INSERT INTO "students" ("last_name", "first_name", "classroom_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["last_name", "aaa"], ["first_name", "aaa"], ["classroom_id", 26], ["created_at", "2016-08-10 21:09:17.897997"], ["updated_at", "2016-08-10 21:09:17.897997"]]
SQL (0.2ms) INSERT INTO "absences" ("class_time", "status", "student_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["class_time", 1], ["status", "Αδικαιολόγητη"], ["student_id", 51], ["created_at", "2016-08-10 21:09:17.902018"], ["updated_at", "2016-08-10 21:09:17.902018"]]
(11.4ms) commit transaction
=> true
HOWEVER
when I get this hash through the form submission the update doesn't happen and no "absences" are getting created. Here is what the console looks like:
Processing by ClassroomsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"blabla",
"classroom"=>{"students_attributes"=>{"0"=>{"absences_attributes"=>{
"0"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"1", "status"=>"valid"},
"1"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"2", "status"=>"valid"},
"2"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"3", "status"=>"valid"},
"3"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"4", "status"=>"valid"},
"4"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"5", "status"=>"valid"},
"5"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"6", "status"=>"valid"},
"6"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"7", "status"=>"valid"}},
"id"=>"50"}}}, "id"=>"27"}
Classroom Load (0.2ms) SELECT "classrooms".* FROM "classrooms" WHERE "classrooms"."id" = ? LIMIT 1 [["id", 27]]
(0.1ms) begin transaction Student Load
(0.3ms) SELECT "students".* FROM "students" WHERE "students"."classroom_id" = ? AND "students"."id" = 50 [["classroom_id", 27]]
(0.1ms) commit transaction
Here is my Classrooms Controller
class ClassroomsController < ApplicationController
def new
#classroom = Classroom.new
#students = 30.times {#classroom.students.build}
end
def create
#classroom = Classroom.new(classroom_params)
if #classroom.save
redirect_to #classroom
else
flash.now[:danger] = "Try again."
render "new"
end
end
def show
#classroom = Classroom.find(params[:id])
end
def data
#classroom = Classroom.find(params[:id])
#classroom.students.each { |student| 7.times { student.absences.build } }
end
def update
#classroom = Classroom.find(params[:id])
#classroom.update_attributes(classroom_params)
redirect_to #classroom
end
private
def classroom_params
params.require(:classroom).permit(:id, :grade_id, :rank, students_attributes:
[:id, :classroom_id, :first_name, :last_name, absences_attributes:
[:id, :student_id, :date, :status, :class_time]])
end
end
Classroom Model
class Classroom < ActiveRecord::Base
# belongs_to :grade
has_many :students, inverse_of: :classroom, dependent: :destroy
accepts_nested_attributes_for :students, allow_destroy: true,
reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}}
has_many :absences, through: :students
accepts_nested_attributes_for :absences, allow_destroy: true,
reject_if: proc { |a| a[:status].blank? }
validates :rank, presence: true
end
Student Model
class Student < ActiveRecord::Base
belongs_to :classroom, inverse_of: :students
has_many :absences, inverse_of: :student
accepts_nested_attributes_for :absences, allow_destroy: true,
reject_if: proc { |a| a[:status].blank? }
# validates :first_name, presence: true
# validates :last_name, presence: true
def full_name
return last_name + " " + first_name
end
end
Absence Model
class Absence < ActiveRecord::Base
belongs_to :student, inverse_of: :absences
# validates :date, presence: true
# validates :class_time, presence: true
# validates :status, presence: true, inclusion: { in: ["valid",
# "invalid", "erased"] }
end
I have turned off all validations as to be sure this is not the reason they are not being saved.
Nested form view
<div id="absences" class="tab-pane fade in active">
<h3>Absences</h3>
<br>
<div class="input-group date col-md-3" id="datepicker">
<input type="text" class="form-control">
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
</div>
<%= form_for #classroom do |class_f| %>
<% #classroom.students.each do |student| %>
<div class="student_<%= student.id %>">
<h4><%= student.full_name %></h4>
<div class="absences">
<p>
<% 7.times do |i| %>
<span><%= i + 1 %></span>
<% end %>
</p>
<%= class_f.fields_for :students, student do |student_f| %>
<% student.absences.each_with_index do |absence, i| %>
<div class="school-hour text-center" data-value="<%= i + 1 %>">
<%= fa_icon "plus" %>
<%= fa_stacked_icon "plus", base: "circle-o" %>
<%= fa_icon "minus" %>
<%= student_f.fields_for :absences, absence do |ab_f| %>
<%= ab_f.hidden_field :student_id, value: absence.student_id %>
<%= ab_f.hidden_field :date, class:"input-absence-date" %>
<%= ab_f.hidden_field :class_time, value: i + 1 %>
<%= ab_f.hidden_field :status, class:"input-absence-status" %>
<% end %>
</div>
<% end %>
<% end %>
</div>
</div>
<% end %>
<div class="actions">
<%= button_to "Submit", "#", class:"btn btn-primary"%>
</div>
<% end %>
</div>
The hidden fields without values are getting filled via javascript before form submission. I don't think that relates to the problem though. The params hash comes through, but the absences are not saving.
Without having spent a lot of time looking at this, could this be the problem?
reject_if: proc { |a| a[:status].blank? }
It appears the params are passing in status as "" which .blank? evaluates as true.
Whatever your form is passing in, in your first example you have "status"=>"valid" but in your 2nd example from the form "status"=>""
I found out that the problem was the reject_if on the classroom model.
I was trying to update the absence through the user, I wasn't actually changing the name of the user, and so not passing it as a param. As a result the record didn't pass the reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}} so it didn't reach the absence record at all. I tried putting a :new_record? validation in the reject if along with the other checks, but that didn't work out.
I found the solution in this answer: https://stackoverflow.com/a/13774269/5909738
Awesome and clean. Look at the comments as well.
I'm getting ActiveModel::ForbiddenAttributesError in MicropostsController#create on line #2 in the create action.
Tried also changing f.hidden_field to hidden_field_tag but still getting ForbiddenAttributesError
micropost_controller
def create
tag = Tag.find(params[:micropost][:tag_id])
#micropost = tag.microposts.build(params[:micropost])
#micropost.user_id = current_user.id
if #micropost.save
flash[:success] = "Posted!"
redirect_to root_path
else
render 'static_pages/home'
end
end
tags_controller
def details
#tag = Tag.find(params[:id])
#microposts = #tag.microposts
#micropost = #tag.microposts.build if sign_in?
end
micropost form
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: #micropost %>
<div class="field">
<%= f.text_area :content, placeholder: "Your post" %>
<%= f.hidden_field :tag_id %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
in tags.rb
has_many :microposts, dependent: :destroy
in microposts.rb
belongs_to :user
belongs_to :tag
It seems that you need to delete tag_id from your microposts parameters:
tag = Tag.find(params[:micropost].delete(:tag_id))
#micropost = tag.microposts.build(params[:micropost])
If that won't fix it, just whit-list the params (it's good idea anyway):
micropost_params = params.require(:micropost).permit(:name, :title, ...)
#micropost = tag.microposts.build(micropost_params)
this
def create
tag = Tag.find(params[:micropost][:tag_id])
#...
end
should probably be changed to this
def create
tag = Tag.find(params[:tag_id])
#...
end
Update: Zishe figured it out. Correct params.require code should be:
def adventure_params
params.require(:adventure).permit(:story, :choice, :parent_id, :user_id)
end
with parenthesis instead of a bracket, of course.
Original question:
I am making a form_for that should be submitting 4 attributes to the Adventure model. The adventure model has ancestry. I keep getting wrong number of arguments (4 for 1) based on my params.require method. When I change to requirements down to 1, I see that all the attributes are blank in my database. I know they are in the params but for some reason they are not being saved. Here is my code:
Form
<div class="form">
<%= form_for #adventure do |f| %>
<%= f.label :choice %>
<%= f.text_area :choice %>
<%= f.label :story %>
<%= f.text_area :story %>
<%= f.label :parent_id %>
<%= f.text_field :parent_id %>
<%= f.submit "Post"%>
<% end %>
</div>
Controller
class AdventuresController < ApplicationController
before_filter :authenticate_user!
def home
end
def index
end
def new
#parent_id = params[:parent_id]
#adventure = Adventure.new
end
def show
#adventure = Adventure.find(params[:id])
end
def create
#user = current_user
#adventure = current_user.adventures.build(adventure_params)
if #adventure.save
flash[:success] = "Adventure created!"
redirect_to #adventure
else
flash[:error] = "There was an error"
redirect_to adventures_path
end
end
private
def adventure_params
params.require(:adventure).permit[:story, :choice, :parent_id, :user_id]
end
end
Model
class Adventure < ActiveRecord::Base
has_ancestry
belongs_to :user
validates :user_id, presence: true
validates :parent_id, presence: true
end
I have no idea why I am getting wrong number of arguments since the attributes show up in the params.
Change permit[...] to:
.permit(:story, :choice, :parent_id, :user_id)
How can I upload multiple images from a file selection window using Rails 4 and CarrierWave? I have a post_controller and post_attachments model. How can I do this?
Can someone provide an example? Is there a simple approach to this?
This is solution to upload multiple images using carrierwave in rails 4 from scratch
Or you can find working demo :
Multiple Attachment Rails 4
To do just follow these steps.
rails new multiple_image_upload_carrierwave
In gem file
gem 'carrierwave'
bundle install
rails generate uploader Avatar
Create post scaffold
rails generate scaffold post title:string
Create post_attachment scaffold
rails generate scaffold post_attachment post_id:integer avatar:string
rake db:migrate
In post.rb
class Post < ActiveRecord::Base
has_many :post_attachments
accepts_nested_attributes_for :post_attachments
end
In post_attachment.rb
class PostAttachment < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
belongs_to :post
end
In post_controller.rb
def show
#post_attachments = #post.post_attachments.all
end
def new
#post = Post.new
#post_attachment = #post.post_attachments.build
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
params[:post_attachments]['avatar'].each do |a|
#post_attachment = #post.post_attachments.create!(:avatar => a)
end
format.html { redirect_to #post, notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
private
def post_params
params.require(:post).permit(:title, post_attachments_attributes: [:id, :post_id, :avatar])
end
In views/posts/_form.html.erb
<%= form_for(#post, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<%= f.fields_for :post_attachments do |p| %>
<div class="field">
<%= p.label :avatar %><br>
<%= p.file_field :avatar, :multiple => true, name: "post_attachments[avatar][]" %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
To edit an attachment and list of attachment for any post.
In views/posts/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<% #post_attachments.each do |p| %>
<%= image_tag p.avatar_url %>
<%= link_to "Edit Attachment", edit_post_attachment_path(p) %>
<% end %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>
Update form to edit an attachment views/post_attachments/_form.html.erb
<%= image_tag #post_attachment.avatar %>
<%= form_for(#post_attachment) do |f| %>
<div class="field">
<%= f.label :avatar %><br>
<%= f.file_field :avatar %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Modify update method in post_attachment_controller.rb
def update
respond_to do |format|
if #post_attachment.update(post_attachment_params)
format.html { redirect_to #post_attachment.post, notice: 'Post attachment was successfully updated.' }
end
end
end
In rails 3 no need to define strong parameters and as you can define attribute_accessible in both the model and accept_nested_attribute to post model because attribute accessible is deprecated in rails 4.
For edit an attachment we cant modify all the attachments at a time. so we will replace attachment one by one, or you can modify as per your rule, Here I just show you how to update any attachment.
If we take a look at CarrierWave's documentation, this is actually very easy now.
https://github.com/carrierwaveuploader/carrierwave/blob/master/README.md#multiple-file-uploads
I will use Product as the model I want to add the pictures, as an example.
Get the master branch Carrierwave and add it to your Gemfile:
gem 'carrierwave', github:'carrierwaveuploader/carrierwave'
Create a column in the intended model to host an array of images:
rails generate migration AddPicturesToProducts pictures:json
Run the migration
bundle exec rake db:migrate
Add pictures to model Product
app/models/product.rb
class Product < ActiveRecord::Base
validates :name, presence: true
mount_uploaders :pictures, PictureUploader
end
Add pictures to strong params in ProductsController
app/controllers/products_controller.rb
def product_params
params.require(:product).permit(:name, pictures: [])
end
Allow your form to accept multiple pictures
app/views/products/new.html.erb
# notice 'html: { multipart: true }'
<%= form_for #product, html: { multipart: true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
# notice 'multiple: true'
<%= f.label :pictures %>
<%= f.file_field :pictures, multiple: true, accept: "image/jpeg, image/jpg, image/gif, image/png" %>
<%= f.submit "Submit" %>
<% end %>
In your views, you can reference the images parsing the pictures array:
#product.pictures[1].url
If you choose several images from a folder, the order will be the exact order you are taking them from top to bottom.
Some minor additions to the SSR answer:
accepts_nested_attributes_for does not require you to change the parent object's controller. So if to correct
name: "post_attachments[avatar][]"
to
name: "post[post_attachments_attributes][][avatar]"
then all these controller changes like these become redundant:
params[:post_attachments]['avatar'].each do |a|
#post_attachment = #post.post_attachments.create!(:avatar => a)
end
Also you should add PostAttachment.new to the parent object form:
In views/posts/_form.html.erb
<%= f.fields_for :post_attachments, PostAttachment.new do |ff| %>
<div class="field">
<%= ff.label :avatar %><br>
<%= ff.file_field :avatar, :multiple => true, name: "post[post_attachments_attributes][][avatar]" %>
</div>
<% end %>
This would make redundant this change in the parent's controller:
#post_attachment = #post.post_attachments.build
For more info see Rails fields_for form not showing up, nested form
If you use Rails 5, then change Rails.application.config.active_record.belongs_to_required_by_default value from true to false (in config/initializers/new_framework_defaults.rb) due to a bug inside accepts_nested_attributes_for (otherwise accepts_nested_attributes_for won't generally work under Rails 5).
EDIT 1:
To add about destroy:
In models/post.rb
class Post < ApplicationRecord
...
accepts_nested_attributes_for :post_attachments, allow_destroy: true
end
In views/posts/_form.html.erb
<% f.object.post_attachments.each do |post_attachment| %>
<% if post_attachment.id %>
<%
post_attachments_delete_params =
{
post:
{
post_attachments_attributes: { id: post_attachment.id, _destroy: true }
}
}
%>
<%= link_to "Delete", post_path(f.object.id, post_attachments_delete_params), method: :patch, data: { confirm: 'Are you sure?' } %>
<br><br>
<% end %>
<% end %>
This way you simply do not need to have a child object's controller at all! I mean no any PostAttachmentsController is needed anymore. As for parent object's controller (PostController), you also almost don't change it - the only thing you change in there is the list of the whitelisted params (to include the child object-related params) like this:
def post_params
params.require(:post).permit(:title, :text,
post_attachments_attributes: ["avatar", "#original_filename", "#content_type", "#headers", "_destroy", "id"])
end
That's why the accepts_nested_attributes_for is so amazing.
Also I figured out how to update the multiple file upload and I also refactored it a bit. This code is mine but you get the drift.
def create
#motherboard = Motherboard.new(motherboard_params)
if #motherboard.save
save_attachments if params[:motherboard_attachments]
redirect_to #motherboard, notice: 'Motherboard was successfully created.'
else
render :new
end
end
def update
update_attachments if params[:motherboard_attachments]
if #motherboard.update(motherboard_params)
redirect_to #motherboard, notice: 'Motherboard was successfully updated.'
else
render :edit
end
end
private
def save_attachments
params[:motherboard_attachments]['photo'].each do |photo|
#motherboard_attachment = #motherboard.motherboard_attachments.create!(:photo => photo)
end
end
def update_attachments
#motherboard.motherboard_attachments.each(&:destroy) if #motherboard.motherboard_attachments.present?
params[:motherboard_attachments]['photo'].each do |photo|
#motherboard_attachment = #motherboard.motherboard_attachments.create!(:photo => photo)
end
end
Here is my second refactor into the model:
Move private methods to model.
Replace #motherboard with self.
Controller:
def create
#motherboard = Motherboard.new(motherboard_params)
if #motherboard.save
#motherboard.save_attachments(params) if params[:motherboard_attachments]
redirect_to #motherboard, notice: 'Motherboard was successfully created.'
else
render :new
end
end
def update
#motherboard.update_attachments(params) if params[:motherboard_attachments]
if #motherboard.update(motherboard_params)
redirect_to #motherboard, notice: 'Motherboard was successfully updated.'
else
render :edit
end
end
In motherboard model:
def save_attachments(params)
params[:motherboard_attachments]['photo'].each do |photo|
self.motherboard_attachments.create!(:photo => photo)
end
end
def update_attachments(params)
self.motherboard_attachments.each(&:destroy) if self.motherboard_attachments.present?
params[:motherboard_attachments]['photo'].each do |photo|
self.motherboard_attachments.create!(:photo => photo)
end
end
When using the association #post.post_attachments you do not need to set the post_id.
I am a newbie to Ruby on Rails and have scoured Stackoverflow and the internet to the best of my abilities and am still stumped.
In my set-up, a Rating belongs_to a Product and has_many Comments. I'm using simple-form and trying to use nested fields_for to add RatingComment through the Rating form. Interestingly, when using the singular form of :rating_comment, the field is displayed. But as expected, I get the unpermitted parameter error when trying to save. When I use plural :rating_comments, the field disappears. This is similar to this SO posting, but adding #rating.rating_comments.build to new action still does not work for me. I've tried restarting the server many times, and even reset the database to no avail. Would appreciate any assistance as I've been struggling with this issue for the past few days.
Note: I've also taken out what I think is irrelevant code from the snippets below. If I need to show more information, please do let me know. Thanks in advance!
routes.rb
resources :ratings, only: [:new, :create, :edit, :update, :destroy] do
resources :rating_comments, shallow: true
end
rating.rb
class Rating < ActiveRecord::Base
belongs_to :product
belongs_to :user
has_many :rating_comments, foreign_key: "rating_id", dependent: :destroy
accepts_nested_attributes_for :rating_comments, reject_if: :all_blank
end
rating_comment.rb
class RatingComment < ActiveRecord::Base
belongs_to :rating
validates :rating_id, presence: true
end
ratings_controller.rb
class RatingsController < ApplicationController
before_action :signed_in_user, only: [:create, :new, :show]
def new
#product = Product.find(params[:id])
#rating = #product.ratings.new
#rating.rating_comments.build
end
def create
#product = Product.find(params[:product_id])
#rating = #product.ratings.build(rating_params)
#rating.user_id = current_user.id
...
private
def rating_params
params.require(:rating).permit(:user_id, :product_id, :rating, rating_comments_attributes: [:rating_id, :content])
end
end
ratings/_new_rating_form.html.erb
<%= simple_form_for([#product, #rating], html: { class: 'form-horizontal' }) do |f| %>
<%= f.error_notification %>
<%= f.input :rating, collection: 1..10, as: :radio_buttons,
item_wrapper_class: 'inline', checked: 5 %>
<%= f.simple_fields_for :rating_comments do |rc| %>
<fieldset>
<%= rc.input :content, label: "Comments" %>
</fieldset>
<% end %>
<%= f.error :base %>
<%= f.button :submit, "Submit" %>
<% end %>
Very embarrassed to admit that it turns out that I had the view written in the wrong action. Once I put it in the new.html, it finally worked.