NoMethodError in Submissions#show - ruby-on-rails

I'm getting the following error:
NoMethodError in Submissions#show
undefined method `comment_path'
I can login, enter a title and URL, and post a comment. When I hit the "Create Comment button"
this is where it errors out:
<%= link_to 'delete', comment, method: :delete, data: { confirm: 'are you sure?'} %>
Other than the error, I'm trying to ADD a Comment not DELETE one?
_comment.html.erb
<%= div_for(comment) do %>
<div class="comments-wrapper clearfix">
<div class="null-left">
<p><small> <%= comment.user.email %> <strong><%=
time_ago_in_words(comment.created_at) %></strong> ago </small></p>
<p class="lead"><%= comment.body %></p>
</div>
</div>
<% if comment.user == current_user %>
<%= link_to 'delete', comment, method: :delete, data: { confirm:
'are you sure?'} %>
<% end %>
<% end %>
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def create
#submission = Submission.find(params[:submission_id])
#comment = #submission.comments.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #submission, notice: 'Comment was successfully created.' }
else
format.html { render :new }
end
end
end
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
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:submission_id, :body, :user_id)
end
end
submission_controller.rb
class SubmissionsController < ApplicationController
before_action :set_submission, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#submissions = Submission.all
end
def show
end
def new
#submission = current_user.submissions.build
end
def edit
end
def create
#submission = current_user.submissions.build(submission_params)
respond_to do |format|
if #submission.save
format.html { redirect_to #submission, notice: 'Submission was
successfully created.' }
format.json { render :show, status: :created, location: #submission
}
else
format.html { render :new }
format.json { render json: #submission.errors, status:
:unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #submission.update(submission_params)
format.html { redirect_to #submission, notice: 'Submission was
successfully updated.' }
format.json { render :show, status: :ok, location: #submission }
else
format.html { render :edit }
format.json { render json: #submission.errors, status:
:unprocessable_entity }
end
end
end
def destroy
#submission.destroy
respond_to do |format|
format.html { redirect_to submissions_url, notice: 'Submission was
successfully destroyed.' }
format.json { head :no_content }
end
end
def upvote
#submission = Submisson.find{params[:id]}
#submission.upvote_by current_user
redirect_to :back
end
def downvote
#submission = Submisson.find{params[:id]}
#submission.downvote_by current_user
redirect_to :back
end
private
def set_submission
#submission = Submission.find(params[:id])
end
def submission_params
params.require(:submission).permit(:title, :url)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :submissions do
member do
put "Like", to: "submission#upvote"
put "Dislike", to: "submission#downvote"
end
resources :comments
end
root to: "submissions#index"
end

For delete, you need to pass submission id like
Your code
<%= link_to 'delete', comment, method: :delete, data: { confirm: 'are you sure?'} %>
After modified
<%= link_to 'Delete', [comment.submission, comment], method: :delete, data: { confirm: 'Are you sure?' } %>
On the comment form
<%= f.hidden_field :user_id, value: current_user.id %>
Create action on comment controller, remove this two lines
#comment = #submission.comments.new(comment_params)
#comment.user = current_user
After update delete link then test for comment create if not creating comment still then follow the below code.
Now your comment create action look like this
def create
#submission = Submission.find(params[:submission_id])
respond_to do |format|
if #submission.comments.create(comment_params)
format.html { redirect_to #submission, notice: 'Comment was successfully created.' }
else
format.html { render :new }
end
end
end
That code from my project which already working, if not working on your side then if have your public repository then post URL or post full error trace.
Update Based on GitHub Link
If you run the rake routes then you will see the comment delete routes format like
DELETE /submissions/:submission_id/comments/:id(.:format) comments#destroy
You need to pass submission_id plus id for comment delete
Update link_to delete looks like this
<%= link_to 'Delete', [comment.submission, comment], method: :delete, data: { confirm: 'Are you sure?' } %>
And your destroy action looks like this on the comments_controller
def destroy
#submission = Submission.find(params[:submission_id])
#comment = #submission.comments.find(params[:id])
#comment.destroy
redirect_to submission_path(#submission)
end
Hope it helps

Related

No route matches {:action=>"new", :controller=>"profiles", :id=>"address"}, missing required keys: [:user_id]

I work with Device and just added the 'wicked' gem to my Rails app. In my RegistrationsController I have defined the following:
class Users::RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
super
end
def update
super
end
protected
def after_sign_up_path_for(resource)
user_steps_path
end
def after_update_path_for(resource)
new_user_profile_path(current_user.id)
end
end
Basically I wish my form to have one further step after sign up, which would be the address:
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :address
def show
#user = current_user
render_wizard
end
end
After the User has given his address, I want him/her to be redirected to their profile, where they can also give the information about themselves. My thinking, this is an update action in my RegistrationsController. Or how do I redirect to the profile, after my multistep form is finilised, meaning the step address is done? Here is address.html.erb:
<%= form_for #user, url: wizard_path do |f| %>
<div class="field">
<%= f.label :street %>
<%= f.text_area :street %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
For now ActionContoller complains about my header routes and looks for id address and I don't get why... Here is my ProfilesContorller:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def show
#user = User.eager_load(:profile).find(params[:user_id])
#profile = #user.profile
#review = Review.new
#reviews = Review.where(profile: #profile)
end
def new
#user = current_user
#profile = Profile.new
end
def edit
#profile = #user.profile
end
def create
#user = current_user
#profile = #user.build_profile(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to user_profile_path(current_user.id), notice: 'Profile was successfully created.' }
format.json { render :show, status: :created, location: #profile }
else
format.html { render :new, notice: 'Did not save' }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to user_profile_path(current_user.id), notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: #profile }
else
format.html { render :edit }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
def destroy
#profile.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_profile
#profile = current_user.profile
end
def profile_params
params.permit(:about, :avatar)
end
end
And here is the error part in my header.html.erb
<% if current_user.profile == nil %>
<li><span class="bg-primary text-white rounded"><%= link_to 'Create profile', new_user_profile_path%></span></li>
<% else %>
<li><span class="bg-primary text-white rounded"><%= link_to 'My profile', user_profile_path(#user) %></span></li>
<% end %>
<li><span class="bg-primary text-white rounded"><%= link_to 'Log out', destroy_user_session_path, method: :delete %></span></li>
ActionController basically complains about the second line and the "new_user_profile_path". How did address got into profiles contoller -> new -> id and how do I procees with the error mentioned in the title. Thank you!
As per your Error, user_id is missing in your route
Try, new_user_profile_path(#user) in second line
So finally it should be <%= link_to 'Create profile', new_user_profile_path(#user)%>

Can't multiple destroy with checkboxes

I need to multiple delete tasks with checkboxes, when i do this have an error
Have tasks and checkboxes for every task, when clicked on checkbox and then click the "Delete selected" button it must be deleted all checked tasks
NoMethodError in TasksController#delete_multiple
undefined method `destroy'
here is my request
{"utf8"=>"✓",
"_method"=>"delete",
"authenticity_token"=>"Bc2lZKUDVOjkQ0DYTDNI8TVliMaDKb+z2wz46RJeFqFol8WyEABA8sAz+WPCQOD2V0SEyqSHAryuoYQ6nvk4sA==",
"cb_tasks"=>["1", "3", "4"],
"commit"=>"Delete selected"}
and
my task_controller
class TasksController < ApplicationController
before_action :set_task, only: [:show, :edit, :update, :destroy]
# GET /tasks
# GET /tasks.json
def index
#tasks = Task.all
end
# GET /tasks/1
# GET /tasks/1.json
def show
end
# GET /tasks/new
def new
#task = Task.new
end
# GET /tasks/1/edit
def edit
end
# POST /tasks
# POST /tasks.json
def create
#task = Task.new(task_params)
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render :show, status: :created, location: #task }
else
format.html { render :new }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tasks/1
# PATCH/PUT /tasks/1.json
def update
respond_to do |format|
if #task.update(task_params)
format.html { redirect_to #task, notice: 'Task was successfully updated.' }
format.json { render :show, status: :ok, location: #task }
else
format.html { render :edit }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tasks/1
# DELETE /tasks/1.json
def destroy
#task.destroy
respond_to do |format|
format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
format.json { head :no_content }
end
end
# multiple delete with checkboxes
def delete_multiple
#tasks = Task.find(params[:cb_tasks])
#tasks.destroy() // **here is a problem**
respond_to do |format|
format.html { redirect_to tasks_url, notice: 'Tasks was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_task
#task = Task.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def task_params
params.require(:task).permit(:title, :description, :priority, :due, :done)
end
end
my task.rb
class Task < ApplicationRecord
def destroy
Task.find(params[:cb_tasks]).destroy
flash[:success] = "Material destroyed."
redirect_to tasks_url
end
end
my index.html.rb
<%= form_tag delete_multiple_tasks_path, method: :delete do %>
<div class="CSSTableGenerator" >
<table >
<tr>
<td>Tasks</td>
</tr>
<% #tasks.each do |task| %>
<tr>
<td><%= check_box_tag "cb_tasks[]", task.id %></td>
<td><%= link_to task.title, task %></td>-->
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Destroy', task, method: :delete, data: {confirm: 'Are you sure?'} %></td>
</tr>
<% end %>
</table>
</div>
<%= submit_tag "Delete selected" %>
<% end %>
my routes
resources :tasks do
collection do
delete 'delete_multiple'
end
end
Why it can't undefined method `destroy' ?
Can anyone help me?
The problem is below line
#tasks = Task.find(params[:cb_tasks])
#tasks.destroy() // **here is a problem**
You can modify this like below
Task.where(id: params[:cb_tasks]).destroy_all
I think will help
instead of overwrite destroy method in model side you can do this and i would suggest you not to overwrite destroy however if you overwrite destroy method than you are not passing params[:cb_tasks] to this method and in Task.find(params[:cb_tasks]).destroy this line fails to execute because it does not get params[:cb_tasks] here in model
so you can do this like -
def delete_multiple
#tasks = Task.find(params[:cb_tasks])
#tasks.destroy_all // **replace it**
respond_to do |format|
format.html { redirect_to tasks_url, notice: 'Tasks was successfully destroyed.' }
format.json { head :no_content }
end
end
I find how it just works. I deleted method destroy the model
and in controller do this
def delete_multiple
Task.where(id: params[:cb_tasks]).destroy_all
end
Thanks for all your answers, you are the best!

updating cart via button

I'm trying to be on that page right before the checkout, where you can modify the quantity and update all the prices accordingly. Now my "Update" button, updates 'something' but it's not what i'm trying to achieve, it sends me on a line_items show page that i don't even want to have (i'm keeping it for now to avoid the missing template error). The rails documentation isn't helping me ... well anyway, the code is this
<ul>
<% #cart.line_items.each do |item| %>
<%= form_for(item) do |f| %>
<li><%= f.number_field :quantity, :value => item.quantity %> x <%= item.product.name %>
<%= item.total_price %> </li>
<% end %>
<%= submit_tag "Update" %>
<% end %>
<br><strong>Total Price:</strong> <%= #cart.total_price %>
</ul>
<%= button_to "Checkout", new_order_path, method: :get, data: { confirm: "Are you sure?" } %>
<%= button_to 'Empty cart', #cart, method: :delete, data: { confirm: 'Are you sure?' } %>
<%= link_to 'Back', categories_path %>
Thank you !
edited
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create, :update, :destroy]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render :show, status: :created, location: #line_item }
else
format.html { render :new }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #cart, notice: 'Line item was successfully updated.' }
format.json { render :show, status: :ok, location: #line_item }
else
format.html { render :edit }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url, notice: 'Line item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:product_id, :cart_id, :order_id)
end
end
Just do redirect after you update an item. And provide correct line_item_update_params method that permites quantity param. Your controller should look like that:
class ItemsController < ApplicationController
def update
item = Item.find(params[:id])
item.update(line_item_update_params)
redirect_to :back # this is the key line of code
end
...
private
# it is used for creating
def line_item_params
params.require(:line_item).permit(:product_id, :cart_id, :order_id)
end
# it is used for updating
def line_item_update_params
params.require(:line_item).permit(:quantity)
end
...
end

how to link to a nested route path inside a loop?

In my application I have stories and substories. Substories are nested inside stories and on the storiesindex.html.erb. I'm looping trough all the stories, and inside I'm looping through all the substories.
here is the code:
<% #stories.each do |story| %>
<%= story.title %>
<%= story.plot %>
<%= link_to 'Show', story_path(story) %>
<%= link_to 'Edit', edit_story_path(story) %>
<%= link_to "Delete", story_path(story), method: :delete, data: { confirm: "Are you sure?" } %>
<% story.substories.each do |substories| %>
<%= substories.title %>
<%= substories.subplot %>
<% end %>
<% end %>
<%= link_to 'New Story', new_story_path %>
This works fine, but I want to link to the edit page of each substory by passing the following argument inside the second loop:
<%= link_to 'Edit', edit_story_substory_path(substory.story, substory) %>
I get a NameError in Stories#index undefined local variable or method 'substory', however this work fine in the substories index.html.erb file.
I've also tried the following:
<%= link_to 'Edit', edit_story_substory_path(#substory.story, #substory) %>
for which I get a NoMethodError in Stories#index undefined method 'story' for nil:NilClass
Here are my routes models and controllers:
#routes.rb
resources :stories do
resources :substories
end
#story.rb
has_many :substories
#substory.rb
belongs_to :story
stories_controller.erb
before_action :set_story, only: [:show, :edit, :update, :destroy]
def index
#stories = Story.all
end
def show
#substories = Substory.where(story_id: #story.id).order("created_at DESC")
end
def new
#story = Story.new
end
def edit
end
def create
#story = Story.new(story_params)
respond_to do |format|
if #story.save
format.html { redirect_to root_path, notice: 'Story was successfully created.' }
format.json { render :show, status: :created, location: root_path }
else
format.html { render :new }
format.json { render json: root_path.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #story.update(story_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#story.destroy
respond_to do |format|
format.html { redirect_to stories_url, notice: 'Story was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_story
#story = Story.find(params[:id])
end
def story_params
params.require(:story).permit(:title, :plot)
end
substories_controller.erb
before_action :set_substory, only: [:show, :edit, :update, :destroy]
before_action :set_story
def index
#substories = Substory.all
end
def show
end
def new
#substory = Substory.new
end
def edit
end
def create
#substory = Substory.new(substory_params)
#substory.user_id = current_user.id
#substory.story_id = #story.id
if
#substory.save
redirect_to #story
else
render 'new'
end
end
def update
respond_to do |format|
if #substory.update(substory_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#substory.destroy
redirect_to root_path
end
private
def set_story
#story = Story.find(params[:story_id])
end
def set_substory
#substory = Substory.find(params[:id])
end
def substory_params
params.require(:substory).permit(:title, :subplot)
end
What am I missing?
<% story.substories.each do |substory| %>
<%= substory.title %>
<%= substory.subplot %>
<% if substory %>
<%= link_to 'Edit', edit_story_substory_path(substory.story, substory) %>
<% end %>
<% end %>
You just made a typo. #substory would work too if you declare it on your Stories#index

How to force rank songs by vote?

So, I have an app that allows users to up vote/like songs (using this gem). However, I'd like the songs with higher votes to be ranked up the list. As currently, they only appear in the order in which they were uploaded. How do I accomplish this?
songs#index.html.erb
<div id="layout-1">
<div class="left-side">
<h3>Songs</h3>
<ol>
<% #songs.each do |song| %>
<li><%= link_to song.title, song %><br></li>
<%=link_to '&#9650'.html_safe, vote_for_song_path(song), :remote => true, :method => :put %>
<%#=link_to '&#9660'.html_safe, vote_against_song_path(song), :remote => true, :method => :put %> |
Submitted <%= time_ago_in_words(song.created_at) + " ago" %>
<span class="comments"> | <%= pluralize(song.comments.size, 'comment') %></span> | <span class="votes"><%= pluralize(song.votes.count, 'like') %></span><br />
<%#= link_to 'Show', song, class: "button small secondary" %>
<%= link_to('Edit', edit_song_path(song), class: "button small secondary") if can? :update, song %>
<%= link_to('Destroy', song, method: :delete, data: {confirm: 'Are you sure?'}, class: "button small secondary") if can? :destroy, song %>
<% end %>
</ol>
</div>
<div class="right-side">
<%= image_tag('delorean.jpg')%>
</div></div>
<br />
songs_controller.rb
class SongsController < ApplicationController
before_filter :authenticate_user!, only: [:create ,:edit, :update, :destroy, :vote_for_song]
before_action :set_song, only: [:show, :edit, :update, :destroy, :vote_for_song]
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
def vote_against
#song = Song.find(params[:id])
current_user.vote_against(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
# GET /Songs
# GET /Songs.json
def index
#songs = Song.all
end
# GET /Songs/1
# GET /Songs/1.json
def show
#comment = Comment.new(song: #song)
end
# GET /Songs/new
def new
#song = Song.new
end
# GET /Songs/1/edit
def edit
end
# POST /Songs
# POST /Songs.json
def create
#song = Song.new(song_params)
respond_to do |format|
if #song.save
format.html { redirect_to #song, notice: 'Song was successfully created.' }
format.json { render action: 'show', status: :created, location: #song }
else
format.html { render action: 'new' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Songs/1
# PATCH/PUT /Songs/1.json
def update
respond_to do |format|
if #song.update(song_params)
format.html { redirect_to #song, notice: 'Song was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# Song /Songs/1
# Song /Songs/1.json
def destroy
#song.destroy
respond_to do |format|
format.html { redirect_to songs_url }
format.json { head :no_content }
end
end
private
def set_song
#song = Song.find(params[:id])
end
def song_params
params.require(:song).permit(:title, :artist, :bio, :track, :user_id)
end
end
Your Song model should have a plusminus field or somesuch (looking at the gem briefly, that looks like plusminus, which is the sum of up plus down votes), which counts the number of thumbs-ups a given song has received. Then, simply query with a sort on that field:
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
#song.plusminus = #song.voted_for
#song.save
respond_to do |format|
format.js { render 'update_votes' }
end
end
def index
#songs = Song.order("plusminus")
end

Resources