I'm having some issues deleting my comments with Ajax. I think I'm close but not sure and would like some advice. Still getting used to jquery and such. I can remove the comment via ajax but not actually delete the record itself so maybe its a simple syntax issue.
destroy.js.erb
$('#remove_comment').remove();
I think I need to tag this with the comment ID but I'm having issues being as the comments are nested under the Pit model.
_comment.html.erb
<div class = "well", id = "remove_comment">
<p>
<%= comment.body %>
<p>posted by: <%= comment.user.name %></p>
<div class = "response">
<p class = "like-response">Was this response persuading to you?</p>
<%= link_to "Yes", pit_comment_like_path(#pit, comment), method: :put %>
<%= link_to "No", pit_comment_dislike_path(#pit, comment), method: :put %>
</div>
<div class = "response-convince">
<p class = "dislike-comment">
<%= comment.get_dislikes.size %> users found this response unpersuasive
</p>
<p class = "like-comment">
<%= comment.get_likes.size %> users found this response persuasive</p>
</p>
</div>
<p>
<%if comment.user == current_user %>
<%= link_to 'Destroy Comment', [#pit, comment],
method: :delete,
data: { confirm: 'Are you sure?' }, remote: true, class: "btn btn-default" %>
</p>
<% end %>
</div>
Comments Controller
def destroy
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.destroy
respond_to do |format|
format.html {redirect_to pit_path(#pit)}
format.js {}
end
Logs seem to be working properly
Started DELETE "/pits/398/comments/63" for 127.0.0.1 at 2014-09-11 12:31:08 -0500
Processing by CommentsController#destroy as JS
Parameters: {"pit_id"=>"398", "id"=>"63"}
Pit Load (0.1ms) SELECT "pits".* FROM "pits" WHERE "pits"."id" = ? LIMIT 1 [["id", 398]]
Comment Load (0.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."pit_id" = ? AND "comments"."id" = ? LIMIT 1 [["pit_id", 398], ["id", 63]]
(0.1ms) begin transaction
ActsAsVotable::Vote Load (0.1ms) SELECT "votes".* FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? [["votable_id", 63], ["votable_type", "Comment"]]
SQL (0.3ms) DELETE FROM "comments" WHERE "comments"."id" = ? [["id", 63]]
(3.0ms) commit transaction
Rendered comments/destroy.js.erb (0.5ms)
Completed 200 OK in 13ms (Views: 3.9ms | ActiveRecord: 3.7ms)
This is the associated markup I have in pits/show.html.erb
<h3>Responses</h3>
<div id = "comment_body">
<%= render #pit.comments %>
</div>
<%= render partial: "comments/form" %>
pit.rb
class Pit < ActiveRecord::Base
validates :topic, :author, :summary, presence: true
acts_as_votable
has_many :comments
belongs_to :user
mount_uploader :image, ImageUploader
end
comment.rb
class Comment < ActiveRecord::Base
acts_as_votable
belongs_to :pit
belongs_to :user
end
Everything inserts correctly with my create.js.erb. I just need to remove it and I think I need to pass in the comment ID or something to that effect. Any advice here would be appreciated. Thanks.
Actually, the comment is being DELETED as logs shows the query:
SQL (0.3ms) DELETE FROM "comments" WHERE "comments"."id" = ? [["id", 63]]
I guess your jQuery doesn't remove the appropriate comment after the callback. You can try changing view code of _comment.html.erb:
<div class = "well", id = "remove_comment_<%= comment.id %>">
<p>
<%= comment.body %>
And then your destroy.js.erb:
$("#remove_comment_<%= #comment.id %>").remove(); // Since #comment will be available in the variable here!
create a link_to with a data-id attribute, when clicked use jquery to make a GET request to your controller.
First, create a route for the delete action in your config/routes.rb:
get 'delete_comment' => 'comments#delete_comment'
Next, add a method to your controller (assumably CommentsController):
def delete_comment
#comment = Comment.find(params[:id])
#comment.destroy
end
Now, set up a link in your view:
= link_to "Remove Comment", "#", :class => "remove_comment", :'data-id' => #comment.id
Now set up the jquery GET request to fire when you click on the link:
$(".remove_comment").click(function(event){
event.preventDefault();
$.get("/delete_comment", {id: $(this).attr("data-id") } );
});
In this example, you would need to rename your delete.js.erb file to delete_comment.js.erb
Related
I'm implementing comments as a nested resource for an events app and hitting one issue after another. Initially it worked fine, however, the only functionality they had was create & destroy. I want to add an edit function using Ajax/remote: true for same page editing (never done it before) and I've hit a wall. The edit link_to doesn't/has never worked and now even the create function doesn't work. This is what's coming through on the development log -
Processing by CommentsController#create as JS
Parameters: {"utf8"=>"✓", "comment"=>{"body"=>"Comment."}, "commit"=>"Create Comment", "event_id"=>"27"}
[1m[36mComment Load (0.1ms)[0m [1m[34mSELECT "comments".* FROM "comments" WHERE "comments"."id" = ? LIMIT ?[0m [["id", nil], ["LIMIT", 1]]
Completed 404 Not Found in 1ms (ActiveRecord: 0.1ms)
ActiveRecord::RecordNotFound (Couldn't find Comment with 'id'=):
I've tried all sorts of different parameters via trial and error but the 'id' issue keeps springing up. Here's my code -
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :create, :edit, :update, :destroy]
def create
#event = Event.find(params[:event_id])
#comment = #event.comments.create(comment_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to #event
else
render 'new'
end
end
# GET /comments/1/edit
def edit
#event = #comment.event
#comment = #event.comments.find(params[:id])
respond_to do |f|
f.js
f.html
end
end
def show
end
def update
if #comment.update(comment_params)
redirect_to #event, notice: "Comment was successfully updated!"
else
render 'edit'
end
end
def destroy
#event = Event.find(params[:event_id])
#comment = #event.comments.find(params[:id])
#comment.destroy
redirect_to event_path(#event)
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def set_event
#event = Event.find(params[:event_id])
end
def comment_params
params.require(:comment).permit(:name, :body)
end
end
_comment.html.erb
<div class="comment clearfix">
<div class="comment_content">
<div id="<%=dom_id(comment)%>" class="comment">
<p class="comment_name"><strong><%= comment.name %></strong></p>
<p class="comment_body"><%= comment.body %></p>
</div>
<p><%= link_to 'Edit', edit_event_comment_path([comment.event, comment]), id: "comment", remote: true %></p>
<p><%= link_to 'Delete', [comment.event, comment],
method: :delete,
class: "button",
data: { confirm: 'Are you sure?' } %></p>
</div>
</div>
_form.html.erb
<%= simple_form_for([#event, #comment], remote: true) do |f| %>
<%= f.label :comment %><br>
<%= f.text_area :body %><br>
<br>
<%= f.button :submit, label: 'Add Comment', class: "btn btn-primary" %>
<% end %>
edit.js.erb
$('#comment').append('<%= j render 'form' %>');
I think I'm getting mixed up with the 'id's for this thing and how to get the remote: true function working on the page. I don't want to accept defeat but I may have to if I don't get this working.
UPDATE -
When I try and edit an existing comment I get this in my development log -
Started GET "/events/27%2F32/comments/27/edit" for ::1 at 2017-05-24 12:28:20 +0100
Processing by CommentsController#edit as JS
Parameters: {"event_id"=>"27/32", "id"=>"27"}
[1m[36mComment Load (0.1ms)[0m [1m[34mSELECT "comments".* FROM "comments" WHERE "comments"."id" = ? LIMIT ?[0m [["id", 27], ["LIMIT", 1]]
Completed 404 Not Found in 1ms (ActiveRecord: 0.1ms)
ActiveRecord::RecordNotFound (Couldn't find Comment with 'id'=27):
The route doesn't make sense - "/events/27%2F32/comments/27/edit" - the comment id should be 32 and the event id 27.
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { omniauth_callbacks: "omniauth_callbacks", registrations: "registrations" }
resources :users
# the above resource draws out routes for user profiles
resources :events do
resources :comments
resources :bookings
end
root 'events#index'
change
before_action :set_comment, only: [:show, :create, :edit, :update, :destroy]
to
before_action :set_comment, only: [:show, :edit, :update, :destroy]
you can't set comment when you are creating it.
Also, as discussed in the comments, your edit link should be,
<%= link_to 'Edit', [comment.event, comment], id: "comment", remote: true %>
I have a div in a parent view that renders a show partial. In this show partial, I have a button that should change the parent's partial to render the 'form' partial to edit the object, but I keep getting jammed up because it seems that the 'form' partial's form_for is missing the #project object.
How can I pass this object to the 'form' partial? Am I missing something else?
I am rather new to using AJAX. Happy to provide more information if you need.
The error I am getting in the server terminal is
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
routes.rb
get 'switchProjectView', to: 'projects#switch_main_view'
resources :projects
projects_controller.rb
class ProjectsController < ApplicationController
def new
#project = Project.new
end
def create
#project = Project.new(project_params)
if #project.save
flash[:success] = "New Project Added"
redirect_to #project
else
flash[:danger] = "Project Not Added. Please Try Again"
end
end
def show
#project = Project.find(params[:id])
end
def index
#projects = Project.all
end
def update
#project = Project.find(params[:id])
if #project.update_attributes(project_params)
redirect_to #project
else
render 'edit'
end
end
def edit
end
def switch_main_view
respond_to do |format|
format.html
format.js
end
end
def project_params
params.require(:project).permit(:main_contact_name, :id, :main_contact_phone, :main_contact_email, :project_name)
end
end
show.html.erb
<div class="body">
<div class="center jumbotron heading-jumbo">
<h1><%= #project.project_name %></h1>
</div>
<div class="body-jumbo jumbotron" id='project-details'>
<%= render "projects/show" %>
</div>
</div>
switch_main_view.js.erb
$('#project-details').html("<%= j render :partial => 'projects/form' %>");
_form.html.erb
<%= form_for(#project) do |f| %>
<%= f.label :project_name %>
<%= f.text_field :project_name, class: 'form-control'%>
<%= f.label :main_contact_name %>
<%= f.text_field :main_contact_name, class: 'form-control'%>
<%= f.label :main_contact_phone %>
<%= f.text_field :main_contact_phone, class: 'form-control'%>
<%= f.label :main_contact_email %>
<%= f.text_field :main_contact_email, class: 'form-control'%>
<%= f.submit 'Save Project', class: 'btn btn-primary'%>
<% end %>
_show.html.erb
<div class='text-center center'>
<h3><strong>Project Information</strong></h2>
</div>
<h2>Start Date: Launch Date:</h1>
<span class='pull-right jumbo-btn-span'><%= link_to "Edit Project Information", switchProjectView_path(#project), remote: true, class:'btn btn-primary jumbo-btn' %></span>
<h2>Primary Conact's Name: <%= #project.main_contact_name %></h2>
<h2>Primary Conact's Phone: <%= #project.main_contact_phone %></h2>
<h2>Primary Conact's Email: <%= #project.main_contact_email %></h2>
Well, with each request, you need to re-initialize the variable in your controller method. In your case, you need to do the following:
def switch_main_view
#project = Project.new
respond_to do |format|
format.html
format.js
end
end
Doing so will enable you to get rid of the error: First argument in form cannot contain nil or be empty, but that won't enable you to do what you are actually trying to do.
When you use link_to, by default it goes for an HTML request as you can see in Rails logs, something like following will appear:
Processing by ProjectsController#switch_main_view as HTML
In order to get the JS response, you need to tell link_to that you are up for a JS response, not for an HTML response, and you can do by passing format: :js in link_to like:
<%= link_to "Edit Project Information", switchProjectView_path(#project, format: :js), remote: true, class:'btn btn-primary jumbo-btn' %></span>
remote: true will be there to make sure that you aren't reloading the contents of the page, rather you are trying to fetch something from the server in the background.
Your request "switchProjectView_path(#project)" only send object id to server, so you need to load the object to present it in view for response.
1. First the route should look like this so that, the url could contain object id:
get 'switchProjectView/:id', to: 'projects#switch_main_view', as:"switchProjectView"
2. You have to load the object in controller:
def switch_main_view
#project = Project.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
Try passing the variable when calling the partial:
$('#project-details').html("<%= j render :partial => 'projects/form', locals: {project: #project} %>");
I followed the instructions in this question's answer by emmanuel and the form now finds the Category ID and submits it but does not find the Sub Category ID associated with the Category and does not save it.
The params are taken which can be noted by this,
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PTRTGGblf3HoWNXmanKl8TIP7F4j/QKTLN2Wd6oKSQWSXV27qioztUpXgb6YjHEroaWf8dgTzUIgQiRBK2XxWQ==", "post"=>{"title"=>"200k", "description"=>"FMxd123", "category_id"=>"2", "subcategory_id"=>"9"}, "commit"=>"Create Post"}
It then shows the error message on my screen (with my error partial) that "Sub Category must exist. The SQL output is like so:
(0.2ms) begin transaction
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
(0.0ms) rollback transaction
Rendering posts/new.html.erb within layouts/application
Rendered shared/_errors.html.erb (0.8ms)
Category Load (0.1ms) SELECT "categories".* FROM "categories"
CACHE (0.0ms) SELECT "categories".* FROM "categories"
SubCategory Load (0.1ms) SELECT "sub_categories".* FROM "sub_categories" WHERE "sub_categories"."category_id" = ? [["category_id", 1]]
SubCategory Load (0.1ms) SELECT "sub_categories".* FROM "sub_categories" WHERE "sub_categories"."category_id" = ? [["category_id", 2]]
SubCategory Load (0.1ms) SELECT "sub_categories".* FROM "sub_categories" WHERE "sub_categories"."category_id" = ? [["category_id", 3]]
My Posts.coffee:
jQuery ->
subcat = $('#subcategory-select').html()
$('#category-select').change ->
cat = jQuery('#category-select').children('option').filter(':selected').text()
options = $(subcat).filter("optgroup[label='#{cat}']").html()
if options
$('#subcategory-select').html(options)
else
$('#subcategory-select').empty()
And the part where category_id and sub_category_id are taken in the form with select boxes:
<p>
<%= f.label :category_id%>
<%= f.collection_select(:category_id, Category.all, :id, :name,
{ prompt: 'Select a category' }, { id: 'category-select' }) %>
</p>
<p>
<%= f.label :subcategory_id%>
<%= f.grouped_collection_select :subcategory_id, Category.all, :sub_categories,
:name, :id, :name, { include_blank: 'Select a sub category' },
{ id: 'subcategory-select' } %>
</p>
Confused as to how it isn't working because it made my category_id get saved when it wasn't working. Any ideas?
Gone through your code and I found some errors.
Here are the changes you should make to make your project work.
As you mentioned, it is not any jquery issue.
Error1:-
You have taken the subcategory model name as SubCategory and table is sub_categories, so the foreign key should be sub_category_id, but you have taken subcategory_id.
So either you have to change the column in the database, or tell rails to take the name.
Here are the changes to tell rails about it.
post.rb
class Post < ApplicationRecord
belongs_to :category
# belongs_to :sub_category
belongs_to :sub_category, class_name: 'SubCategory', foreign_key: 'subcategory_id'
end
sub_category.rb
class SubCategory < ApplicationRecord
belongs_to :category
# has_many :posts, :primary_key => "subcategory_id"
has_many :posts, class_name: 'Post', primary_key: 'id', foreign_key: 'subcategory_id'
end
Check the lines commented.
Now the post show view also has some errors which I solved.
Error2:-
posts/show.html.erb:
<% content_for :title, #post.title %>
<% navigation_add #post.title, post_path(#post) %>
<h2 align="center">Title: <%= #post.title %></h2>
<div class="well col-xs-8 col-xs-offset-2">
<h4 class="center description"><strong>Description:</strong></h4>
<hr>
<%= simple_format(#post.description) %>
<hr>
<p>Post ID: <%=#post.id%></p>
<hr>
<div class="post-actions">
<%= link_to "Edit this post", edit_post_path(#post), class: "btn btn-xs btn-primary" %>
<%= link_to "Delete this post", post_path(#post), method: :delete,
data: { confirm: "Are you sure you want to delete the post?"},
class: "btn btn-xs btn-danger" %>
<%= link_to "View all posts", posts_path, class: "btn btn-xs btn-success" %>
</div>
</div>
Last but not the least, your seeds.rb is wrong.
Error3:-
category_1 = Category.where(name:"cat1").first_or_create(name:"cat1")
category_2 = Category.where(name:"cat2").first_or_create(name:"cat2")
#SUB
# 1
SubCategory.where(name: 'g', category_id: category_1.id).first_or_create
SubCategory.where(name: 'er', category_id: category_1.id).first_or_create
#L2
SubCategory.where(name: 'tu', category_id: category_2.id).first_or_create
SubCategory.where(name: 'dual', category_id: category_2.id).first_or_create
Add this script to posts/new.html to get your dropdown work.
<script type="text/javascript">
$(document).ready(function() {
var subcat;
subcat = $('#subcategory-select').html();
return $('#category-select').change(function() {
var cat, options;
cat = jQuery('#category-select').children('option').filter(':selected').text();
options = $(subcat).filter("optgroup[label='" + cat + "']").html();
if (options) {
return $('#subcategory-select').html(options);
} else {
return $('#subcategory-select').empty();
}
});
});
</script>
Here is the working image:
I'm new on RoR, and I try to build a classic web app with post & user.
There is a model & controller(Onlines) that allow the user to put his posts on a common wall with new informations own to this action.
I'm currently trying to modify a nested form associated with this action(Onlines), by modifying the model Onlines.
But I can't access to this action of my controller, and I don't understand why ?
My code ::
Onlines controller :
class OnlinesController < ApplicationController
before_action :set_online
def edit
end
private
def set_online
#post = Post.find(params[:post_id])
#online = Online.find_by(params[:id])
end
end
Post controller :
class PostsController < ApplicationController
before_action :set_online
def show
#online.post_id = #post.id
end
private
def set_online
#onlines = Online.find_by(id: params[:id])
end
end
Views/posts/show : `
<div class="btn-group" role="group" aria-label="...">
<%= link_to '- taked - ', edit_online_path(#online), data: { confirm: 'Confirmer la mise en ligne de #{#title}?' }, class: "btn btn-primary " %>
</div>
Views/onlines/edit :
<%= simple_form_for([#post, #onlines]) do |f| %>
<div class="row">
<div class="col-md-12">
<div id="Order">
<%= f.simple_fields_for :orders do |order| %>
<%= render 'orders_fields', f: order %>
<%end%>
<div class="Order_links">
<%= link_to_add_association 'Ajouter une part', f, :orders, class: "btn btn-default" %>
</div>
</div>
</div>
</div>
<div class="form-group text-center">
<%= f.submit "Pusher", class: 'btn btn-success' %>
</div>
<% end %>
Routes:
Rails.application.routes.draw do
get 'profiles/show'
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users, :controllers => { registrations: 'registrations' }
resources :posts do
resources :comments
resources :onlines
end
get ':pseudo', to: 'profiles#show', as: :profile
get ':pseudo/edit', to: 'profiles#edit', as: :edit_profile
patch ':pseudo/edit', to: 'profiles#update', as: :update_profile
get ':post_id/online/new', to: 'online#new', as: :new_online
post ':post_id/online/:id/edit', to: 'onlines#edit', as: :edit_online
root 'posts#index'
So if you can guide me to succeed this action it would be wonderful, thanks !
Firstly, always refer to your models in singular form (Online in your case) as that is what Rails expects and controller's in plural as you have stated. Be careful of your "before_action :set_online" statement as it is using the 'find' method for defining #post and will cause an exception if a param isn't passed in! Also, your route is only showing a get request to get you to your edit_online page. You'll then need a 'post' route linked to your 'update' action that will submit the data to your application after the user submits his/her form! Provide the rest of your routes and I'll take a deeper look but also clarify your question a bit. If you're just trying to go from one action in one controller to another action in a different controller you're looking to use the "redirect_to" statement.
My app is setup where a user owns a task and other user's can volunteer to complete these tasks. My models are setup as so:
User
class User < ActiveRecord::Base
has_many :participations, foreign_key: :participant_id
has_many :owned_tasks, class_name: "Task", foreign_key: :owner_id
end
Participation (Join Table)
class Participation < ActiveRecord::Base
enum status: [:interested, :selected]
belongs_to :task
belongs_to :participant, class_name: "User"
end
Task
class Task < ActiveRecord::Base
enum status: [:open, :in_progress, :complete]
has_many :participations
has_many :participants, through: :participations, source: :participant
# Dynamically generates relations such as 'selected_participants'
Participation.statuses.keys.each do |status|
has_many "#{status}_participants".to_sym,
-> { where(participations: { status: status.to_sym }) },
through: :participations,
source: :participant
end
belongs_to :owner, class_name: "User"
end
What I would like do is simply allow users to click a button to volunteer for a task within that particular task's show view.
I can accomplish this with ease inside my rails console:
user = User.first
task = Task.first
user.owned_tasks << task
user_2 = User.find(2)
task.participants << user_2
Where I get stuck is trying to figure out how to setup the necessary controller code to get this to work. I'm also not sure how/where to create the conditional that checks if a user is already participating in a task is_participating?. Does it go in the join mode Participation or the Task table?
I think I have a vague idea on what the view should look like:
Task - Show View
<% unless current_user == #task.owner %>
<div class="volunteer-form">
<% if current_user.is_participating? %>
<%= render 'cancel' %>
<% else %>
<%= render 'volunteer' %>
<% end %>
</div>
<% end %>
_volunteer.html.erb:
<%= form_for(current_user.participations.build(participant_id: current_user), remote: true) do |f| %>
<div><%= f.hidden_field :participant_id %></div>
<%= f.submit "Volunteer" %>
<% end %>
_cancel.html.erb:
<%= form_for(current_user.participations.find_by(participant_id: current_user), html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Cancel" %>
<% end %>
JS
// create.js.erb
$(".volunteer-form").html("<%= escape_javascript(render('tasks/volunteer')) %>");
// destroy.js.erb
$(".volunteer-form").html("<%= escape_javascript(render('tasks/cancel')) %>");
From your view looks like is_participating? belongs in the User model, it should probably be something along these lines:
def is_participating?(task_id)
participations.where(task_id: task_id).exists?
end
As for the controller code you probably want something along these lines:
class ParticipationsController
# Note I assume you have access to current_user here
def create
participation = current_user.participations.create(participation_params)
respond_to do |format|
format.js
end
end
def destroy
participation = current_user.participations.find(params[:id])
participation.destroy
respond_to do |format|
format.js
end
end
protected
def participation_params
params.require(:participation).permit :task_id
end
end
On _volunteer.html.erb (Note that you now have to pass the task into the partial):
<%= form_for(current_user.participations.build, remote: true) do |f| %>
<%= f.hidden_field :task_id, value: task.id %>
<%= f.submit "Volunteer" %>
<% end %>