Empty Post in Rails 5.2 - ruby-on-rails

I'm trying to add the helper _form of my Comment model inside Advertisement view. I call the helper <%= render 'comments/form', comment: #comment %>in the route /advertisement/:id
So here is my comments _form :
<%= form_with(model: comment, local: true, url: "/comments") do |form| %>
<% if comment && comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= form.label :content %>
<%= form.text_area :content, class:"form-field" %>
</div>
<%= form.hidden_field :advertisment_id, value:params[:id] %>
<div class="actions">
<%= form.submit "Envoyer", class:"btn btn-primary", url: 'comments' %>
</div>
<% end %>
I specify the url: "/comments" because I'm at /advertisment/:id and by default the action is aimed to here.
But when the post reached my comment controller, it can't read the params.
ActionController::ParameterMissing in CommentsController#create
The strange part is that I've access to the params :
{"utf8"=>"✓", "authenticity_token"=>"0+swOqHPEHN2Gwh0TO3iC7VPRz4ROLoBlkaMkOdnjjYxWHoDer7AwrgnQpu+9VHfSY90yMSRsNp8ojvPJxuzmQ==", "content"=>"Test", "advertisment_id"=>"1", "commit"=>"Envoyer"}
So here is the comment controller :
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# [...]
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params.merge(:user_id => #session_user.id))
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# [...]
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:content, :advertisment_id)
end
end
Thanks a lot for your help

It probably because your #comment is nil so that form_with works like the old form_tag helper.
By using form_with, a field like <%= form.text_field :content %>
If your model is presented, it will generate <input type="text" name="comment[content]" />
If your model is not presented, it will generate <input type="text" name="content" />
In the second case, your strong params check will reject the naked params
To be able to solve it, simply assign a valid model to your render
<%= render 'comments/form', comment: Comment.new %>

According to the docs here, if you specific url option in form_with without the scope option, the params received will be missing prefixes in there name. Therefore
params.require(:comment).permit(:content, :advertisment_id)
will raise an error since the params does not include comment.
You should remove url option in your form_with or use url and scope options at the same time.

Related

param is missing or the value is empty: room

i created an edit page to edit the room(model) and update the form to change the current name and current capacity to whatever we wish but i am getting an error
ActionController::ParameterMissing in RoomsController#edit
param is missing or the value is empty: room
rooms_controller.rb
class RoomsController < ApplicationController
before_action :set_room, only: %i[show edit update]
def index
#rooms = Room.all
end
def show
end
def new
#room = Room.new
end
def create
#room = Room.new(room_params)
respond_to do |format|
if #room.save
format.html { redirect_to room_url(#room), notice: "Room was created Successfully" }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
def edit
respond_to do |format|
if #room.update(room_params)
format.html { redirect_to room_url(#room), notice: "Room was successfully updated!" }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
private
def set_room
#room = Room.find(params[:id])
end
def room_params
params.require(:room).permit(:name, :capacity)
end
end
edit.hml.erb
<h2>Edit Room</h2>
<%= render "form", room: #room %>
_form.html.erb
<%= form_with(model: room) do |form| %>
<% if room.errors.any? %>
<div style="color: red">
<h2><%= pluralize(room.errors.count, "errors") %> Prohibited this Room from saving</h2>
<ul>
<% room.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :name, style: "display: block" %>
<%= form.text_field :name %>
</div>
<div>
<%= form.label :capacity, style: "display: block" %>
<%= form.number_field :capacity %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
i am using the same partial _form.html.erb for both new.html.erb and edit.html.erb , is it because of using same partial form for edit and new or there is some other reason?
new.html.erb
<h1>New Room</h1>
<%= render "form", room: #room %>
You're using the wrong action.
In Rails flavored REST the edit action responds to a GET /rooms/:id/edit request and just renders the form. It should also be idempotent. There is no room parameter since you're not responding to a form submission.
Updating the resource is done in the update method (PATCH /rooms/:id).
class RoomsController < ApplicationController
# ...
# you can actually completely omit this method
# Rails will implicitly render edit.html.erb anyways
# GET /rooms/1/edit
def edit
end
# PATCH /rooms/1
def update
# you don't need to use MimeResponds if you're only responding to HTML requests. KISS
if #room.update(room_params)
redirect_to #room, notice: "Room was successfully updated!"
else
render :edit, status: :unprocessable_entity
end
end
# ...
end

Couldn't find Comment with 'id'=3 with nested resources

im getting this error:
https://imgur.com/a/Mrvkm2Z
I can create comments in mi course post but i can't edit them because of this error
I don't know how to solve this, I was looking everywhere but nothing that helps me solve the problem
EDIT
here is my code in comments controller
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#course = Course.find(params[:course_id])
#comment = #course.comments.build
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#course = Course.find(params[:course_id])
#comment = #course.comments.build(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #course, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:title, :body)
end
end
so i think the problem might be in create and new, i dont know how to connect the models with one-to-many, i was able to create comments in my course but when i wanted to edit 1 of the comments apiers that error and in every comment i click to edit sends me to the same url with the same error id=3 not found
Also this are my html code(maybe the errors can be there too):
<%= form_for #comment, :url => course_comments_path(params[:course_id]) do |f| %>
<% if comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title, id: :comment_title %>
</div>
<div class="field">
<%= f.label :body %>
<%= f.text_area :body, id: :comment_body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and the show.html for my courses:
<% if current_user%>
<p id="notice"><%= notice %></p>
<p>
<h1><%= #course.name %></h1>
</p>
<p>
<h2>Comentarios del curso:</h2>
</p>
<p>
<% #course.comments.each do |comment| %>
<h3><%= comment.title %></h3>
<p><%= comment.body %></p>
<%if current_user.admin%>
<%= link_to 'Edit', edit_course_comment_path(#course) %>
<%end%>
<%end%>
</p>
<%if current_user.admin %>
<%= link_to 'Postear', new_course_comment_path(#course)%>
<%= link_to 'Edit', edit_course_comment_path%>
<%= link_to 'Back', authenticated_root_path %>
<%else%>
<%= link_to 'Postear', new_course_comment_path(#course) %>
<%= link_to 'Back', authenticated_root_path %>
<%end%>
First off you have a strange mix of shallow nesting and deep nesting. Shallow nesting is a routing option that effects the nesting of member routes.
resources :courses do
# GET|PUT|PATCH|DELETE /courses/:course_id/comments/:id
# GET /courses/:course_id/comments/:id/edit
resources :comments
# GET|PUT|PATCH|DELETE /comments/:id
# GET /comments/:id/edit
resources :comments, shallow: true
end
I would generally recommend shallow nesting - unless the child only can exist in the scope of its parent or is only unique in the scope of its parent. And your controller is setup for shallow nesting. Just make sure you edit those comments from the scaffold so that they actually document the right paths.
Besides the routes you also need to use the correct link helpers:
# deep nesting
link_to 'Edit', edit_course_comment_path(#course, #comment)
# shallow nesting
link_to 'Edit', edit_comment_path(#comment)
If you really need to support both you can use the polymorpic route helpers:
link_to 'Edit', [:edit, #course, #comment]
To create forms for nested resources pass an array containing the parent and child:
form_for([#course, #comment])
# or in rails 5+
form_with(model: [#course, #comment])
This works perfectly fine with both deep and shallow nesting as well as Rails compacts the array. This also lets you use the same form partial for creating and updating.
Explicitly passing the URL for a form in Rails is redundant 99% of the time. If you just follow the conventions Rails is smart enough to figure out the correct path for creating and updating.
I think this line
<%= link_to 'Edit', edit_course_comment_path(#course) %>
should be
<%= link_to 'Edit', edit_course_comment_path(#course, comment) %>
You need both ids of the course and the comment.

nested resource only working on edit not new, rails 5.0.0.1

I have the following resources defined:
resources :buildings do
resources :buildings_regular_hours
end
My models are are follows:
class Building < ApplicationRecord
has_many :building_regular_hours
def to_s
name
end
end
class BuildingsRegularHours < ApplicationRecord
belongs_to :building
end
I am attempting to create a form to allow for creating and editing of BuildingRegularHours. Currently the form I have will display on #edit, but will not display on #new.
new.html.erb:
<%= render 'form', buildings_regular_hour: #buildings_regular_hour, building: #building %>
edit.html.erb:
<h1>Editing Buildings Regular Hour</h1>
<%= render 'form', buildings_regular_hour: #buildings_regular_hour, building: #building %>
<%= link_to 'Back', building_buildings_regular_hour_path(#building) %>
_form.html.erb:
<%= form_for([building,buildings_regular_hour]) do |f| %>
<% if buildings_regular_hour.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(buildings_regular_hour.errors.count, "error") %> prohibited this buildings_regular_hour from being saved:</h2>
<ul>
<% buildings_regular_hour.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :building_id %>
<%= f.text_field :building_id %>
</div>
<div class="field">
<%= f.label :start_date %>
<%= f.date_select :start_date %>
</div>
<div class="field">
<%= f.label :end_date %>
<%= f.date_select :end_date %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
buildings_regular_hours_controller.rb:
class BuildingsRegularHoursController < ApplicationController
before_action :set_buildings_regular_hour, only: [:show, :edit, :update, :destroy]
before_action :set_building
# GET /buildings_regular_hours
# GET /buildings_regular_hours.json
def index
#buildings_regular_hours = BuildingsRegularHours.all
end
# GET /buildings_regular_hours/1
# GET /buildings_regular_hours/1.json
def show
end
# GET /buildings_regular_hours/new
def new
#buildings_regular_hour = BuildingsRegularHours.new
end
# GET /buildings_regular_hours/1/edit
def edit
end
# POST /buildings_regular_hours
# POST /buildings_regular_hours.json
def create
#buildings_regular_hour = BuildingsRegularHours.new(buildings_regular_hour_params)
respond_to do |format|
if #buildings_regular_hour.save
format.html { redirect_to #buildings_regular_hour, notice: 'Buildings regular hours was successfully created.' }
format.json { render :show, status: :created, location: #buildings_regular_hour }
else
format.html { render :new }
format.json { render json: #buildings_regular_hour.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /buildings_regular_hours/1
# PATCH/PUT /buildings_regular_hours/1.json
def update
respond_to do |format|
if #buildings_regular_hour.update(buildings_regular_hour_params)
format.html { redirect_to #buildings_regular_hour, notice: 'Buildings regular hours was successfully updated.' }
format.json { render :show, status: :ok, location: #buildings_regular_hour }
else
format.html { render :edit }
format.json { render json: #buildings_regular_hour.errors, status: :unprocessable_entity }
end
end
end
# DELETE /buildings_regular_hours/1
# DELETE /buildings_regular_hours/1.json
def destroy
#buildings_regular_hour.destroy
respond_to do |format|
format.html { redirect_to buildings_regular_hours_index_url, notice: 'Buildings regular hours was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_buildings_regular_hour
#buildings_regular_hour = BuildingsRegularHours.find(params[:id])
end
def set_building
#building = Building.find(params[:building_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def buildings_regular_hour_params
params.require(:buildings_regular_hour).permit(:building_id, :start_date, :end_date, :sunday_id, :monday_id, :tuesday_id, :wednesday_id, :thursday_id, :friday_id, :saturday_id)
end
end
Having added a BuildingRegularHours via console, I attempted the #edit action, and it works just fine, displaying the form as expected. However, when I attempt the #new action, I receive the following error:
Showing /Users/shawn/Documents/uga/library_hours/app/views/buildings_regular_hours/_form.html.erb where line #1 raised:
undefined method `building_buildings_regular_hours_index_path` for #<#<Class:0x007fe9589e2890>:0x007fe95f9bbb30>
Did you mean? building_buildings_regular_hours_path
building_buildings_regular_hour_path
building_buildings_regular_hours_url
building_buildings_regular_hour_url
Extracted source (around line #1):
1 <%= form_for([building,buildings_regular_hour]) do |f| %>
2 <% if buildings_regular_hour.errors.any? %>
3 <div id="error_explanation">
4 <h2><%= pluralize(buildings_regular_hour.errors.count, "error") %> prohibited this buildings_regular_hour from being saved:</h2>
5
6 <ul>
Trace of template inclusion: app/views/buildings_regular_hours/new.html.erb
I note that I have properly nested the resources in the form_for tag, that both #building and #building_regular_hour are set by the controller, and that I am calling the form in exactly the same way for both #edit and #new. This is all I've had to do previously to make nested resources work, so I'm at a bit of a loss as what to do next.
Please note I have not attempted to make the form work yet - I know there is work to be done there. I just am trying to get #new to display the form.
You need to correct the association
class Building < ApplicationRecord
has_many :buildings_regular_hours
def to_s
name
end
end
class BuildingsRegularHour < ApplicationRecord
belongs_to :building
end
Your model name should always be singular BuildingsRegularHour or it will create issues with routes and associations

Unable to assign a parent id to nested comments, using Ancestry gem (ruby on rails)

I am creating nested comments (like you find on Reddit). I am able to create parent comments, but when I try to create a child comment, it simply renders as a parent comment.
In my rails console, the "ancestry" field comes back "nil".
This is my comments controller:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
def show
#comment = Comment.find(params[:id])
end
def new
#link = Link.find(params[:link_id])
#comment = Comment.new(:parent_id => params[:parent_id])
#comments = Comment.all
end
def create
#link = Link.find(params[:link_id])
#parent = Link.find(params[:link_id]) if params[:link_id]
#parent = Comment.find(params[:comment_id]) if params[:comment_id]
#comment = #parent.comments.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #link, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to :back, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:link_id, :body, :user_id)
end
end
Here is my _comment_form partial
<%= div_for(comment) do %>
<div class="comments_wrapper clearfix">
<div class="pull-left">
<p class="lead"><%= comment.body %></p>
<p><small>Submitted <strong><%= time_ago_in_words(comment.created_at) %> ago</strong> by <%= comment.user.email %></small></p>
<div id="reply" style="display:none;">
<%= form_for [#comment = Comment.new(:parent_id => params[:parent_id])] do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.text_area :body %> <br>
<%= f.submit %>
<% end %>
</div>
</div>
<div class="actions btn-group pull-right">
<button onClick="$('#reply').show()" class="btn btn-sm btn-default">Reply</button>
<% if comment.user == current_user -%>
<%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-sm btn-default" %>
<% end %>
</div>
</div>
<% end %>
These are my routes
Rails.application.routes.draw do
resources :comments
devise_for :users
devise_for :installs
resources :links do
member do
put "like", to: "links#upvote"
put "dislike", to: "links#downvote"
end
resources :comments
end
root to: "links#index"
end
Had this problem before; the answer is here:
Ancestry gem in Rails and Mutli Nesting
The problem with ancestry (this is why we changed back to acts_as_tree) is that you have to define all the ancestors in the ancestry column (as opposed to just the parent_id column of acts_as_tree).
Thus, when you call the .children of an object (where you've literally just populated ancestry with top-level parents) is a list of children for that parent (no others).
What you need is to reference the entire ancestry line. This is quite tricky, but can be achieved using the code below:
#app/views/links/index.html.erb
<%= render #link.comments if #post.comments.any? %>
#app/views/links/_comment.html.erb
<%= comment.title %>
<%= render "form", locals: {link: #link} %>
<%= render comment.children if comment.has_children? # > adds recursion (multi level nesting) %>
#app/views/links/_form.html.erb
<%= form_for link.comments.new do |c| %>
<%= c.text_field :body %>
<%= c.submit %>
<% end %>
The controller is as follows:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#link = Link.find params[:link_id]
#comment = #link.comments.new ancesrtry: parent(params[:parent_id])
end
private
def parent(param)
parents = Comment.find(param).pluck(:parent)
"#{parents}/#{param}" #-> ruby automatically returns last line
end
end
This should set the correct path for you, and the partials should give you the appropriate recursion required for multi level nesting.

Basic Rails - how do automatically assign a new database entry to an associated entry it belongs to?

I'd like to automatically associate a new database entry with the database entry it belongs to without having to make a choice while on the form as the user can only come from the category page, so that once you're in a category and you decide to make a new entry within that category, the newly created entry is automatically within that category upon submission. Can anyone offer any help?
My models are as follows:
class Category < ActiveRecord::Base
has_many :guides
end
class Guide < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :ratings
def average_rating
average = ratings.inject(0.0){ |sum, el| sum + el.value }.to_f / ratings.size
average.round(2)
end
end
The link to create the new guide for the category is pretty standard, though I thought that adding an instance variable might automatically associate the entry with the category though it doesn't:
<%= link_to 'New Guide', new_guide_path(#category) %>
Here is the controller for the guide:
class GuidesController < ApplicationController
before_action :set_guide, only: [:show, :edit, :update, :destroy]
# GET /guides
# GET /guides.json
def index
#guides = Guide.all
end
# GET /guides/1
# GET /guides/1.json
def show
end
# GET /guides/new
def new
#guide = Guide.new
end
# GET /guides/1/edit
def edit
end
# POST /guides
# POST /guides.json
def create
#guide = Guide.new(guide_params)
respond_to do |format|
if #guide.save
format.html { redirect_to #guide, notice: 'Guide was successfully created.' }
format.json { render :show, status: :created, location: #guide }
else
format.html { render :new }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /guides/1
# PATCH/PUT /guides/1.json
def update
respond_to do |format|
if #guide.update(guide_params)
format.html { redirect_to #guide, notice: 'Guide was successfully updated.' }
format.json { render :show, status: :ok, location: #guide }
else
format.html { render :edit }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# DELETE /guides/1
# DELETE /guides/1.json
def destroy
#guide.destroy
respond_to do |format|
format.html { redirect_to guides_url, notice: 'Guide was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guide
#guide = Guide.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def guide_params
params.require(:guide).permit(:name, :category_id, :user_id, :stepOneText, :stepOnePhoto, :stepTwoText, :stepTwoPhoto, :stepThreeText, :stepThreePhoto)
end
end
Form is pretty standard too, is there anything I should put in here to automatically assign it to the category entry it belongs to?
<%= form_for(#guide) do |f| %>
<% if #guide.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#guide.errors.count, "error") %> prohibited this guide from being saved:</h2>
<ul>
<% #guide.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :stepOneText %>
<%= f.text_field :stepOneText %>
</div>
<div class="field">
<%= f.label :stepOnePhoto %>
<%= f.text_field :stepOnePhoto %>
</div>
<div class="field">
<%= f.label :stepTwoText %>
<%= f.text_field :stepTwoText %>
</div>
<div class="field">
<%= f.label :stepTwoPhoto %>
<%= f.text_field :stepTwoPhoto %>
</div>
<div class="field">
<%= f.label :stepThreeText %>
<%= f.text_field :stepThreeText %>
</div>
<div class="field">
<%= f.label :stepThreePhoto %>
<%= f.text_field :stepThreePhoto %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Seems to me that you could go for something like a nested route here :
resources :categories do
resources :guides
end
and then use your new route
<%= link_to 'New Guide', new_category_guide_path(#category) %>
This should make it easier to get the guide's category back when getting the form back.
Assuming that you have a column on your guide table that stores category ID, and your routes are nested as has been recommended, you should be able to add
#guide.category_id = #category.id
To your guides controller create action. And in your form change the first line to
<%= form_for[#category, #guide] do |f| %>
Now this should work
<%= link_to 'new guide', new_category_guide_path(#category) %>
And the current category should be assigned to your guide when it's created.

Resources