So, I'm having Events model which has_many Questions. Relation is the same as in Post->Comment. I've tried to implement some Ajax for Questions, but it seems like I'm missing something, because View doesn't updates without refreshing the page. The same problem with delete method.
Here's my question_controller.rb:
def create
#question = #event.questions.create(question_params)
#question.user_id = current_user.id if current_user
if #question.save
respond_to do |format|
format.html { redirect_to event_path(#event) }
format.js # render questions/create.js.erb
end
else
render 'events/show'
end
end
Question _form.haml:
= simple_form_for [#event, #event.questions.new], remote: true do |f|
= f.input :content, label: 'Your question:', id: 'question_content'
= f.submit class: 'submit_btn'
Question partial _question.haml:
%h4
= question.content
This is how it looks in Events show.haml:
%section#question_section
%h1 Questions:
#questions
= render #event.questions
#question-form
%h1 Submit a question:
= render 'questions/form'
And create.js.erb file:
$('#questions').append("<%= j render partial: #question %>");
$('#question_content').val('');
I've tried few different tutorials, but always had the same problem. View updates only after refreshment. Also it is my second post on Stackoverflow so would be grateful for any suggestions if something is wrong with it.
EDIT 1: mostly I've been following this tutorial: https://pragmaticstudio.com/blog/2015/3/18/rails-jquery-ajax
EDIT 2: create.js.erb seems not to respond, tried to test it with alerts or console log, but without any success. After triggering a button in the console having: "Processing by QuestionsController#create as JS" (so it runs a proper file, but file itself doesn't executes any code). Have no idea why that happening.
So the problem was because of HAML. Had to change my format.js line in the controller to:
formta.js { render layout: false }
Here's the thread that helped to solve this: Rails update.js.erb not executing javascript
Related
I have to ask about something that probably no one uses anymore. I want to display flash[:notice] after successfully AJAX action. I'm aware of this and that one and even this gist but none of them fit my example:
#controller code
def new
#registrant = Registrant.new
respond_to do |format|
format.html
if params[:add_patient_to_caregiver]
format.js { render partial: 'add_patient_to_caregiver' }
end
end
end
#view triggered controller#new action via AJAX
<%= link_to 'Add Patient to Caregiver', patient_to_caregiver_path(add_patient_to_caregiver: true, patient_to_caregiver: registrant.id), method: :get, remote: true %>
I want to have something like format.js { render partial: 'add_patient_to_caregiver', flash[:notice] = 'Patient Added' } to display it in a view. I've come up with a workaround:
_add_patient_to_caregiver.js.erb
$("#add-patient").html("<%= escape_javascript(render :partial => 'registrants/add_patient') %>");
$("#flash-messages").after("<div class='alert alert-success'> Patient Added </div>");
And flash message shows up but there are no close button there. Is there any better way to do so? or how to add close button to that message so that the whole page doesn't reload when it is pressed?
I'm building an Events site using RoR which I've just upgraded to v5.0.1 (not moving to 5.1 just yet). My events show page has a comments section at the foot of the page which, so far, only has a create and delete functionality.
I want to add an Edit/Update function to comments so only the user who created the comment can edit the comment if they see fit. I want them to be able to edit their comment whilst on the same page.
I'm trying to implement these changes using remote: true & Ajax, rather than rely on a gem as it doesn't appear too complex, but I've never done this before and there doesn't appear to be a clear guide via the internet/SO. Here's my views & controller code -
comments_controller.rb
def create
#event = Event.find(params[:event_id])
#comment = #event.comments.create!(params[:comment].permit(:name, :body))
#comment.user_id = current_user.id
redirect_to #event
end
def update
#comment.user = current_user
respond_to do |format|
if #comment.update
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.js { }
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
def destroy
#event = Event.find(params[:event_id])
#comment = #event.comments.find(params[:id])
#comment.destroy
redirect_to event_path(#event)
end
_comments.html.erb
<% if user_signed_in? %>
<p><%= link_to "Edit", remote: true %></p>
<p><%= link_to 'Delete', [comment.event, comment],
method: :delete,
class: "button",
data: { confirm: 'Are you sure?' } %></p>
<% end %>
My understanding is that I need to include a .js.erb file in my views/comments folder to deal with this ( edit.js.erb ?) but what I'm not clear on is exactly what javascript code I need to include in order for this to work. Also, I don't think my controller code above seems right - should this go in the Edit action? Do I also need an Event#show action in my events controller as this is where it sits in the views?
Any assistance would be greatly appreciated.
I realize this doesn't answer your question, but hopefully it'll solve headaches down the road for you as far as reinventing the wheel goes. It's also why (I believe) you're seeing downvotes.
I don't want to use best_in_place gem as it appears to not have been updated for a while and I'm not sure if its the best fit for Rails 5.0.
Gems don't need to have activity to still be useful. By "for a while", you must mean mean "less than 24 hours ago" because I'm seeing plenty of activity over the last month. Once a Gem solves its usually good to go.
https://github.com/bernat/best_in_place/commits/master
Rails 5 still handles POST requests right? Then it should work. best_in_place is more javascript-heavy than anything. https://github.com/bernat/best_in_place/tree/master/lib/best_in_place
The most "daunting" code in there is the helper.rb file, which renders the HTML that hooks into the JS library.
Update:
The comments/edit.js.erb file would be responsible for inserting the form to edit the comment, such as $('div#new_comment').append('<%= j render 'form' %>');
This assumes you're using Rails' conventions in regards to element/ID naming.
If you have a link_to("Edit", edit_comment_path(comment), :remote => true) everything should fire automatically.
Here's an example repo using Rails 4; should be the same for Rails 5, with the exception of (maybe) respond_to blocks? I'm not sure, haven't used Rails 5 yet. Just do a bundle, rake db:setup, and then a rails s; navigate to http://localhost:3000/events and enjoy.
You're on the right track with edit.js.erb. The file should contain JS code to set up the screen for editing, which might be hiding a DIV and displaying an INPUT or TEXTAREA instead, for example.
Of course, the file can also contain Ruby code as well, inside <% %> tags.
Can't seem to figure this one out... In my rails app, I have Post and Comment resources. When a new comment is created, I want to reload the list of comments using AJAX. That part seems to work appropriately—however, when the full page is subsequently reloaded, the list also shows a duplicate of the comment, as shown in this screenshot. Any thoughts on what may be causing this?
(note: deleting one of the comments also deletes the duplicate)
views/users/show.html.haml
= form_for([post, post.comments.build], remote: true) do |f|
= f.text_field :content, placeholder: 'Press ENTER to submit...', class: "comment_content", id: "comment_content_#{post.id}"
- if post.comments
.comments{ id: "comments_#{post.id}" }
- post.comments.each do |comment|
= render post.comments, post: post
views/comments/_comment.html.haml
- unless comment.content == nil
.comment{ id: "comment_#{comment.id}" }
.user-name
= link_to comment.user.identities.first.nickname, comment.user
.comment-content
= comment.content
- if comment.user == current_user
= link_to post_comment_path(post, comment), data: { confirm: "Are you sure?" }, method: :delete, remote: true do
%i.fa.fa-close
controllers/comments_controller.rb
class CommentsController < ApplicationController
before_action :set_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
respond_to do |format|
format.html { redirect_to :back }
format.js
end
else
render root_path
end
end
...
views/comments/create.js.erb
$('#comments_<%= #post.id %>').append("<%=j render #post.comments, post: #post, comment: #comment %>");
$('#comment_content_<%= #post.id %>').val('')
Update
Following #uzaif's suggestion, I replaced ".append" with ".html". This fixed the problem only if I also moved the code out of the _comment partial. Not really an ideal solution... I'd still like to know if/how I could fix the problem and keep my individual comment partial.
The Problem
You are seeing duplicate comments because you are inadvertently rendering your comments twice.
- post.comments.each do |comment|
= render post.comments, post: post
Calling render and passing a collection as the first argument instructs Rails to render all of the comments. Internally Rails will iterate over each comment and render it using the object's partial.
By wrapping this render call (which already has a loop in it) within another loop, you are actually rendering each comment twice.
The Solution
Remove the outer post.comments.each loop and just let the render method do it's thing.
= render post.comments
Rails knows to pass along an local variable named comment to each partial, and you should be able to reference the original post by calling comment.post (assuming comment belongs_to :post).
Be careful how you call render
There are a couple different ways to render partials with data from a collection. Make sure you know which one you are using and don't mix-and-match them.
I describe this in another StackOverflow post.
Resources
http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections
https://stackoverflow.com/a/40412677/1219460
The problem in brief: I'm working on a rails 4 app (4.1.8) and I'm trying to get flash[:notice] and flash[:alert] to show up under a form.
Two controllers: landingpage_controller and contacts_controller. The landingpage_controller serves a static landingpage through its show action and the contacts_controller has new and create actions, to store the contacts in a db table.
On the static landingpage, a modal with id="contact-modal" contains a partial with a simple_form_for #contact (see below). Upon submittal of the form, a db-entry is not created if the fields are not all filled out and a db-entry is created if the fields are filled out. However, no flash messages are displayed.
Wanted output:
Ideally the partial would re-load without leaving/closing the modal, with either: a success message and an empty form or a alert message and the form as it was upon submittal. How do I do this?
The controller: app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
render layout: "contact"
end
def create
#contact = Contact.new
respond_to do |format|
if #contact.save
flash[:notice] = "Success"
format.js
else
flash[:alert] = "Error"
format.js
end
end
end
private
def contact_params
params.require(:contact).permit(:email, :structure, :message_content)
end
end
The form: app/views/contacts/_new.html.haml
= simple_form_for #contact, html: { id: "contact-form"} do |c|
= c.input :email
= c.input :structure
= c.input :message_content
= c.button :submit
.messages-container
= if flash[:notice]
%p
= flash[:notice]
= if flash[:alert]
%p
= flash[:alert]
Routes:
resources :contacts, only: [:new, :create]
I'm aware that a partial reload probably involves AJAX. I've read several StackOverflow questions on this but have not been able to figure it out. See here, here and these two blog-posts: jetthoughts, ericlondon.
Your help is very much appreciated
There are several problems in your code:
views, that start with underscore are called partials and are not full actions, but just parts of reusable view code (you don't redirect to them, instead you use render since you usually don't want a full page reload.
1.1 Rename your _new.html.haml to _form.html.haml
2.1 Create a new view new.html.erb(I guess you have that already, otherwise your new action might not work properly) with content = render 'form'
From what I understand you don't want the modal to close, just to render a form after successful submission or if there is an error.
In that case:
1.create a create.js.erb file in your views/contacts folder
create.js.erb
$("#your_modal_id").html("<%= j( render 'form') %>")
2. change your create action
def create
#contact = Contact.new(contact_params)
respond_to do |format|
if #contact.save
flash[:notice] = "Success"
format.js
else
flash[:alert] = "Error"
format.js
end
end
end
to your form add remote: true
WARNING: This will leave your form filled in even if it is successful.
More about this topic see:
http://guides.rubyonrails.org/v4.1.8/working_with_javascript_in_rails.html#form-for
Hope it helps, and I hope I didn't forget anything
I'm trying to do something fairly simple but I'm not sure the rails way to do it. At its simplest, I have an index page where you can sign up for a mailing list.
I'm trying to set it up so that you can add yourself to the mailing list from the index page without ever seeing the mailing list views. I can submit the data properly using something like:
= form_for #mailing_list, :remote => true do |form|
= if #mailing_list.errors.any?
%ul
= #mailing_list.errors.full_messages.each do |message|
%li
= message
.field
= form.label :email, 'Your email'
= form.text_field :email
= form.submit "Add to Mailing List"
With the controller:
def create
#mailing_list = MailingList.new(params[:mailing_list])
if #mailing_list.save
redirect_to(:root, :notice => 'Mailing list was successfully created.')
else
? How do I return the errors ?
end
end
But I am unable to get the errors back (ie. Email not valid, etc.). Is there a better way to do what I'm attempting? I would just like to be able to call and respond to actions of the MailingList controller from the index page view...
I believe that you are wanting a form that will add someone to a Mailing list without leaving that page.
Better? Hmmm.. Well, I'll tell you what I do and you can decide what you like.
I would use respond_to in the controller to differentiate between the standard html call and the remote js call. Then, I would handle the page changes in the view. I like keeping the display in the views.
Controller:
def create
#mailing_list = MailingList.new(params[:mailing_list])
if #mailing_list.save
respond_to do |format|
format.html { redirect_to(:root, :notice => 'Mailing list was successfully created.') }
format.js { render }
end
else
respond_to do |format|
format.html { render }
format.js { render :errors }
end
end
end
create.js.erb
$('#errors').html('').hide();
$('form').html('Mailing list was successfully created.'); // needs a better element
errors.js.erb
$('#errors').html('<%= escape_javascript(#mailing_list.errors.full_messages.collect { |msg| content_tag :li, msg }.join().html_safe) %>').show();
You can do something with the errors object on #mailing_list, e.g.
flash.now[:error] = #mailing_list.errors.full_messages