Sending update request in Rails 5 edit form using AJAX - javascript

I'm having an issue with an edit form on my page to update and save attributes using AJAX in Ruby on Rails 5. The goal is to render the edit form in the same page and then after editing the information submit the form and have the info show back up. Getting the edit form to show up on the page works perfectly fine but after that it just does nothing.
I have a feeling it has something to with where the form is sending to but I can't seem to figure it out. I have searched all over and it seems there are lots of answers out there for rails 3/4 but the request is different for rails 5. From all the examples I can find, my code looks correct, but clearly I'm missing something. I'm still a beginner rails developer but from my understanding the edit form should send an update request to the controller but it doesn't seem to do so. Any help is appreciated. Code below.
Controller
def create
#properties = Property.new(property_params)
if #properties.save
flash[:success] = "Property created successfully!"
redirect_to properties_path
else
render 'new'
end
end
def edit
#properties = Property.find(params[:id])
respond_to do |format|
format.html { #properties.save }
format.js
end
end
def update
#properties = Property.find(params[:id])
#property.update_attributes(property_params)
respond_to do |format|
format.html { redirect_to property_path }
format.js
end
end
View
<%= link_to fa_icon("edit", text: "Edit Property"),
edit_property_path(#properties), remote: true, class: "btn btn-
primary btn-large btn-ouline" %>
edit.js.erb
$('div#show-edit').replaceWith('<%= j render("edit_prop_form") %>');
update.js.erb
$('#edit_property_<%= #properties.id %>').replaceWith('<%= j render("properties_display") %>');
_edit_prop_form.html.erb partial
<%= bootstrap_form_for(#properties, layout: :horizontal, control_col: "col-sm-4", remote: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :company, class: 'form-control' %>
<%= f.text_field :address1, class: 'form-control' %>
<%= f.text_field :address2, class: 'form-control' %>
<%= f.text_field :city, class: 'form-control' %>
<%= f.text_field :state, class: 'form-control' %>
<%= f.text_field :zipcode, class: 'form-control' %>
<%= f.form_group do %>
<%= f.submit "Edit", class: "btn btn-primary" %>
<% end %>
<% end %>
HTML that edit form renders
<form role="form" class="form-horizontal" id="edit_property_99"
action="/properties/99" accept-charset="UTF-8" data-remote="true"
method="post"><input name="utf8" type="hidden" value="✓"><input
type="hidden" name="_method" value="patch">
TL;DR Edit form renders on page from initial edit button but "Edit" button on the form does not update and save edited info and display original div.

As mr12086 pointed out, in my update method #property should have been #properties. After making the change all worked as expected.

Related

Using ajax to change the state of a button in Ruby on Rails views

I have a setting in which I would like to dynamically change a buttons disabled state. Currently the logic I have looks as follows:
<% if #has_attachment_file_sent %>
<% if current_user.id != #offer.user_id %>
<%= link_to send_signature_requests_path, remote: true, method: :post,
data: { confirm: "Are you sure?" },
id: "signature_request_button",
class: "button is-info is-fullwidth m-t-10 m-b-10" do %>
<span>Send request</span>
<% end %>
<% end %>
<% else %>
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled>Send request</button>
<% end %>
However, the problem with this method is that this only changes the state of the button when you refresh the page. Is there a way to do this kind of Ajax with RoR or what should I do here?
Also tried using javascript as follows:
<script>
$(document).ready(function() {
var has_attachment_file_sent = <%= #has_attachment_file_sent %>
console.log(has_attachment_file_sent);
if(has_attachment_file_sent) {
$('#signature_request_button').attr('disabled', true);
}
})
</script>
but this doesn't seem to be doing anything.
Also here's my controller
def show
#offer = Offer.find(params[:id])
#has_attachment_file_sent = Comment.where(user_id: #offer.user_id).any? {|obj| obj.attachment_file.attached?}
respond_to do |format|
format.html
format.js { render layout: false, content_type: 'text/javascript' }
end
end
First place your html in a partial and wrap the content in div, assume that the partial's name is 'buttons.html.erb'
_buttons.html.erb
<% if #has_attachment_file_sent %>
<% if current_user.id != #offer.user_id %>
<%= link_to send_signature_requests_path, remote: true, method: :post,
data: { confirm: "Are you sure?" },
id: "signature_request_button",
class: "button is-info is-fullwidth m-t-10 m-b-10" do %>
<span>Send request</span>
<% end %>
<% end %>
<% else %>
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled>Send request</button>
<% end %>
<div id="buttons">
<%= render partial: 'buttons' %>
</div>
Add button in view
<%= link_to 'Refresh', show_page_path(id: #offer.id), id: 'btn_call_ajax', remote: true %>
you should adapt show_page_path with your route
def show
#offer = Offer.find(params[:id])
#has_attachment_file_sent = Comment.where(user_id: #offer.user_id).any? {|obj| obj.attachment_file.attached?}
respond_to do |format|
format.html
format.js
end
end
Then you should create a file named show.js.erb that contain the following code:
$('#buttons').html('')
$('#buttons').append("<%= escape_javascript render(:partial => 'buttons') %>");
Oh yeah, how annoying, forgot about that
Maybe something like this inside js.erb
It should work, hacks but I’m sure there is another solution I’m going blank on
# render partial line here
<% if #disabled %>
$(‘#button-id’).prop(“disabled”, true);
<% else %>
$(‘#button-id’).removeAttr(“disabled”)
<% end %>
create the file show.js.erb and in your controller just leave it as format.js without curly braces.
create a partial with
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled="<%= disabled ? “disabled” : “” %>”>Send request</button>
And add a div in original file, wrap rendering of the partial above
<div id=“woohoo”>
<%= render partial: “file_above”, locals: {disabled: true} %>
</div>
Then in that .js.erb file add this $(‘#div-around-button’).html(“<%= j render(‘show’, disabled: #disabled_variable_from_controller) %>”) and it will basically refresh that button with new value that you got from controller 🙂
P.S. I wrote this all on my iPhone so I might have missed small things like syntax

Submit button gets freezed after submitting the form via Ajax

When I submit form using jQuery-Ajax in ROR the submit button gets freezed.
I am practicing "Integrating Ajax and Rails: A Simple Todo List App", provided by GitHub.
class TodosController < ApplicationController
def create
#binding.pry
#todo = Todo.create(todo_params)
respond_to do |format|
format.html {redirect_to home_path}
format.js {}
end
end
private
def todo_params
params.require(:todo).permit(:description, :priority)
end
end
index.html.erb
<h2>Create Todos</h2>
<%= render 'new' %>
<h2>Todos List</h2>
<ul>
<%= render #todos %>
</ul>
_new.html.erb
<%= form_for Todo.new, html: {id: "form1"} do |f| %>
<p>
<%= f.label :description %>
<%= f.text_field :description %>
</p>
<p>
<%= f.label :priority %>
<%= f.text_field :priority %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
_todo.html.erb
<li>
<%= todo.description %><br>
<strong>Priority:</strong><%= todo.priority %><br>
<%= link_to 'done', todo_path(todo) , method: 'delete' %>
</li>
create.js.erb
$("ul").append("<%= j render partial: 'todo', locals: {todo: #todo} %>");
app/assets/javascript/todos.js
$(function(){
$("#form1").submit(function(event){
event.preventDefault();
let method = $(this).attr('method');
let action = $(this).attr('action');
let description = $(this).find('#todo_description').val();
let priority = $(this).find('#todo_priority').val();
let data = $(this).serializeArray();
$.ajax({
method: method,
url: action,
data: data,
dataType: 'script'
});
});
});
The button gets frozen because nowadays there is a jquery script that disables it to prevent multiple submissions. Check for any classes/attributes added to the submit button when it's clicked, and then put some jquery to your create.js.erb to remove them and also clear the fields if you want to submit a new todo item.

Rails 4 Ajax call only works once

I have an app where you can post Links. Each Link has_many Comments
I've set up ajax where a user can upvote a particular comment. Currently, a user can successfully upvote a comment via ajax the first time, but if the user then attempts to upvote a different comment on the same page then the ajax breaks and the value doesn't get updated until the page is refreshed.
comments_controller.rb:
def comment_upvote
#comment = Comment.find(params[:id])
#link = Link.where(id: #comment.link_id)
#comment.upvote_by current_user
respond_to do |format|
format.html {redirect_to link_path(#link)}
format.js {}
end
end
views/comments/_comment.html.erb:
<div class="well">
<h2><%= comment.title %></h2>
<p class="text-muted">Added by <strong><%= comment.author %> <%= comment.author_last_name %></strong> on
<%= l(comment.created_at, format: '%B, %d %Y %H:%M:%S') %></p>
<blockquote>
<p><%= comment.body %></p>
</blockquote>
<p><%= link_to 'reply', new_comment_path(parent_id: comment.id, link_id: #link.id) %></p>
<%= link_to pointup_comment_path(comment.id), method: :put, remote: true do %>
+
<% end %>
<div id="comment-votes">
Votes: <%= comment.get_upvotes.size %>
</div>
views/comments/comment_upvote.js.erb:
$('#comment-votes').html("<%= j render "upvotes", locals: { #comment => #comment } %>")
views/comments/_upvotes.html.erb:
Votes: <%= #comment.get_upvotes.size %>
Is there an easy way to fix this? Let me know if you need extra detail.
The problem here is that there are many divs with id comment-votes. When you try to get the element by id, it always get the same div.
To solve this problem you need to make the id unique per comment.
views/comments/_comment.html.erb:
<div id="comment-votes-<%= comment.id %>">
Votes: <%= comment.get_upvotes.size %>
</div>
After setting the unique comment ids. You just need to change the ajax call.
views/comments/comment_upvote.js.erb:
$("#comment-votes-<%= #comment.id %>").html("<%= j render "upvotes", locals: { #comment => #comment } %>")

has_many and accepts_nested_attributes_for with nested forms and jquery/ajax

I'm trying to create a nested form where there is a "+" button which adds fields via jquery and ajax. I am doing it adding a step at once, so untill now I am able to add a simple text pushing the "+" button, but, as I have just said, I want to add some fields.
I have the followings:
new.html.erb
<h1>New Campaign</h1>
<%= form_for #campaign, html: { multipart: true } do |f| %>
....
<div class="goods">
<%= render "goods/good", f: f, child_index: Time.now.to_i %>
</div>
<div class="actions">
<%= link_to '+', add_good_row_path(params[:campaign]=#campaign, params[:f] = f), remote: true, class: 'btn btn-large btn-success' %>
<%= f.submit 'Crea', class: 'btn btn-large btn-warning' %>
</div>
<% end %>
goods/_good.html.erb
<%= f.fields_for :goods, #campaign.goods.build, child_index: child_index do |good| %>
<%= good.text_field :name, placeholder: 'Nome' %>
<%= good.text_area :description, placeholder: 'Descrizione' %>
<%= good.text_field :cost, placeholder: 'Costo' %>
<% end %>
campaigns_controller.rb
class CampaignsController < ApplicationController
....
def add_good_row
respond_to do |format|
format.js
end
end
end
add_good_row.js.erb
$('.goods').append("hello");
I think that I understood the problem, it is to pass a f variable, a #campaign variable and a child_index to the partial, but how can I do that via jquery?
Hope I was clear...
Have a look at this gem.
I think it's what you are looking for
https://github.com/nathanvda/cocoon

Error display on ajax form in rails not working

I'm using an inline form for users to submit data to a table (note that I'm using CSS rather than html tables to achieve this). When an error is returned by the verification in the model, I want to highlight the input field using the Bootstrap error class and put the error message below the appropriate form field. I'm using AJAX to submit the form.
I'm having problems, this is what I have so far:
Controller:
def create
#travel = Travel.new(params[:travel])
#travel[:user_id] = current_user.id
convert_date # and return
if #travel.save
flash[:notice] = "Successfully saved trip"
#travels = Travel.where("user_id = ?",current_user)
respond_to { |format| format.js }
end
end
JS view:
<% if #travel.errors.any? %>
<% #travel.errors.full_messages.each { |msg| logger.debug(msg) } %>
<% #travel.errors.messages.each do |k,v| %>
<% logger.debug("#tf_#{k}") %>
$(<%= "#tf_#{k}" %>).insertAdjacentHTML("afterbegin","<span class="control-group error"><span class="controls">");
$(<%= "#tf_#{k}" %>).insertAdjacentHTML("beforeend","</span></span>");
$(<%= "#error_#{k}" %>).val("<%= "#{k} #{v}" %>");
<% end %>
<% else %>
$(":input:not(input[type=submit])").val("");
$("#travels_list").html("<%= escape_javascript( render(:partial => "travels") ) %>");
<% end %>
form partial:
<%= form_for #travel, :remote => true, :html => {:class => "form-inline", :id => "new-travel-form"} do |f| %>
<div class="row-fluid">
<span id="tf_city"><%= f.text_field :city, :placeholder => "London, UK", :class => "span3" %></span>
<span id="tf_arrive_date"><%= f.text_field :arrive_date, :class => "span2" %> </span>
<span id="tf_leave_date"><%= f.text_field :leave_date, :class => "span2" %> </span>
<span id="tf_notes"><%= f.text_field :notes, :placeholder => "e.g. staying at the Hilton", :class => "span3" %></span>
<%= f.submit "save", :class => "btn btn-primary span1" %>
</div>
<% end %>
<div class="row-fluid error" id="error_expl">
<span id="error_city" class="help-inline span3"></span>
<span id="error_arrive_date" class="help-inline span2"></span>
<span id="error_leave_date" class="help-inline span2"></span>
<span id="error_notes" class="help-inline span3">test</span>
</div>
The logger.debug in the JS is firing, so I know that the error is getting passed to the JS, but the insertAdjacentHMTL() doesn't seem to be working.
maybe this is not going to answer your question but i hope it could help to improve your code.
First, according to your code i guess you should have some associations like this in the model User:
has_many :travels
And in your model Travel:
belongs_to :user
So, in order to improve your code you can have this in your controller:
respond_to :js, only: [:create]
def new
#travel = current_user.travels.new
end
def create
#travel = current_user.travels.new(params[:travel])
if #travel.save
flash[:notice] = "Successfully saved trip"
#travels = current_user.travels
else
# I guess you should have some code here in case any validation fail. If you dont
# have validations for the model Travel, you don't need the if statement here.
end
end
About your problem, can you clarify what is "#tf_#{k}"?

Categories

Resources