AJAX on dynamic class value for Rails - ruby-on-rails

Short version:
If I have
.favorite-link
= link_to some_path, class: (#condition ? "favorited" : "") do
.star-image
routes.rb
resources :hacks do
post "favorite", on: :member
end
hacks_controller.rb
def favorite
#favorite = Favorite.find_or_initialize_by(user_id: current_user.id, hack_id: params[:id])
if #favorite.persisted?
#favorite.destroy
respond_to do |format|
format.js
end
else
#favorite.save
respond_to do |format|
format.js
end
end
end
favorite.js.coffee
$('.favorite-link a').toggleClass("favorited")
This last bit of code changes EVERY instance. How do I toggle just the one I clicked? Doing `.on 'click', -> $(this).toggleClass("favorited") does weird stuff, like change it only every other time I click it. Plus, the render js is not suited for that way.
Or perhaps a better way to accomplish toggling the class value is: how do I toggle the star using ajax (i.e. make the page evaluate #condition again after clicking the link?)
Irrelevant to the core of the question, but FYI:
SCSS
.favorite-link {
a.favorited {
.star-image {
background-image: url('star-on.png');
}
}
.favorite-link {
a {
.star-image {
background-image: url('star-off.png');
}
}
}

Use jQuery to add the class as part of your Ajax response handler:
$(".star-image").addClass("favorited");
There is also .toggleClass and .removeClass to fill out your implementation.

Related

Rendering template with json params

I have new and create actions like this:
def new
#foo = Foo.new
end
def create
#foo = Foo.new(foo_params)
respond_to do |format|
if #foo.save
format.html { redirect_to root_path }
else
format.html { render :new } //**this line I want to send params**
end
end
end
I have a jbuilder file to new action like this:
new.json.jbuilder
json.foo do
json.a "Some important info"
json.b "Some important info"
end
And rails can't read this file after create's validation fails. How to render a view template (like render :new) and send some json data in this view?
I have a js calling like this:
var json_url = window.location.href + ".json";
var foo;
$.ajax({
url: json_url,
dataType: 'json',
async: false,
success: function(data) {
foo = data.foo;
}
});
If you want Rails to render a file, you'll need to remove the call to redirect_to as it will effectively prevent any rendering.
Furthermore, if you don't want the controller to respond to different formats, it's better to skip the call to respond_to, too.
If you just call render action: :new, the view template will have access to all controller instance variables (like #foo):
json.foo do
json.a #foo.a
json.b #foo.b
end

Rails Ajax Call : Pass JSON to separate controller method

Hey everyone I am having an issue setting up my app. It uses the shopify API and essentially what it does is grab some data via a view and sends it to the controller but I am having issues passing it to another method in the controller to use the API to save the data.
Here is my code :
Controller
class BuilderController < ShopifyApp::AuthenticatedController
def index
urlval = request.fullpath
#urlCheck = urlval.split('/').last
end
def show
url = request.fullpath
#urlID = url.split('/').last
#customers = ShopifyAPI::Customer.search(query: "id:"+ #urlID)
#need to get a way to retrieve the ajax call info here to pass into the update
end
def updateCustomer(notes)
#customers.each do |cus|
cus.note = notes
cus.save()
end
end
def new
notes = params[:notes]
updateCustomer(notes)
render json: notes
end
end
View
<button id="test">TEST</button>
<script>
var butt = document.getElementById('test');
butt.addEventListener("click",function(){
$.ajax({
url: "/builder/new",
type: "GET",
data: {
"notes": [
"test",
"test2"
]
},
success: function(data,text,xhr) {
console.log(text);
console.log(xhr);
console.log(data);
alert('successfully');
},
error: function(data,error){
console.log(data);
console.log(error);
alert("help");
}
});
});
</script>
Rather than a fully separate method, have you looked into the
respond_to method? http://api.rubyonrails.org/classes/ActionController/MimeResponds.html#method-i-respond_to
You could do (assuming html is the primary request type, change if it isn't):
def index
respond_to do |format|
format.html { actions }
format.json { actions }
end
end
This the method we use to accommodate different request types within the same action. Please let me know if I've misinterpreted your question.
you can use this
update_all(updates) public
Updates all records with details given if
they match a set of conditions supplied, limits and order can also be
supplied. This method constructs a single SQL UPDATE statement and
sends it straight to the database. It does not instantiate the
involved models and it does not trigger Active Record callbacks or
validations.
http://apidock.com/rails/v4.0.2/ActiveRecord/Relation/update_all
def new
notes = params[:notes]
#customer.update_all({note: notes})
respond_to do |format|
format.html {}
format.json { json: #customer.json }
end
end

String substitution within ruby array

I have the following code, within which I want to change certain values to csv friendly, e.g., 'nil' to ''. I need to know how to make these changes. Thank you.
def daily_door_schedule
#tickets = Ticket.where(active: true).
pluck(
:door_manufacturer,
:job_number,
:door_style,
:door_allocation_date,
:date_doors_received_in_aub,
:door_delivery_due_date,
:notes
)
respond_to do |format|
format.html
format.csv { render text: #tickets.to_csv }
end
end
This should do it:
#tickets = Ticket.where(active: true).
pluck(
:door_manufacturer,
:job_number,
:door_style,
:door_allocation_date,
:date_doors_received_in_aub,
:door_delivery_due_date,
:notes
).map { |ticket| ticket.map(&:to_s) }

Ajax:success not working in rails app

Within a rails 4 app, I am using a link_to to send an upvote on posts via json.
Here is what I have in my posts controller:
def upvote
#post = Post.find(params[:id])
#post.liked_by current_user
respond_to do |format|
format.html {redirect_to :back }
format.json { render json: { count: #post.get_upvotes.size } }
end
end
Here is what I have in my view
<%= link_to like_post_path(post), method: :put, class: 'vote', remote: true, data: { type: :json } do %>
<%= image_tag('vote.png') %>
<%= content_tag :span, post.get_upvotes.size %>
<% end %>
<script>
$(document)
.on('ajax:send', '.vote', function () { $(this).addClass('loading'); })
.on('ajax:complete', '.vote', function () { $(this).removeClass('loading'); })
.on('ajax:error', '.vote', function(e, xhr, status, error) { console.log(status); console.log(error); })
.on('ajax:success', '.vote', function (e, data, status, xhr) {
$(this).find("span").html(data.count);
$(this).find("img").attr("src", '<%= asset_path 'voted.png' %>');
});
</script>
When I click on the link, the vote goes through as a JSON request, I see this in my log:
Processing by PostsController#upvote as JSON
But for some reason, my snipped of javascript is not working. Neither the counter or the icon update. How can I fix this? Does this have to do with turbolinks, does it have to do with where I am placing the javascript?
In Rails you can perform a similar task by having a JavaScript response. Add in your respond_to a format.js similar to format.html then have a view upvote.js.erb that looks like:
(function() {
var postId = "#post-<%= #post.id %>";
$(postId).find(".vote").find("span").text("<%= #post.get_upvotes.size %>");
$(postId).find(".vote").find("img").attr("src", "<%= asset_path "voted.png" %>");
})();
I changed your call to .html to .text since you're not actually setting any HTML inside the element, there is no reason to call .html.
This post also assumes there is some mechanism to identify the post the vote link belongs to (in the example the parent post element has an ID of "post-#" where # is the ID of the post object).
EDIT
Two changes I'd make if I were working on this project. First I would attach the voted.png path to the .vote element as a data attribute. data-voted-image-src="<%= asset_path "voted.png" %>". Next, I would never pass a number in the return as there is no reason to do so. When the vote is clicked you can handle everything on the front end by assuming the request is successful. Which saves all this potential nastiness. While I realize that changing from what you current have to adding the data attribute isn't a huge leap I just find it more semantic than having it in the JavaScript.
The click action on the vote link then becomes:
// Assume all posts have a class 'post'
// I'm also using 'one' because once they vote they don't need to anymore
$(".post").find(".vote").one("click", function(e) {
var count = parseInt($(this).find("span").text()),
votedSrc = $(this).data("voted-image-src");
$(this).find("img").attr("src", votedSrc);
$(this).find("span").text(count + 1);
});
Now no response from the server is necessary, and you can change your JSON response to {success: true} or something simple.
jQuery is the default rails javascript library. The default rails javascript library used to be prototype, so old tutorials/docs use it. This is what the ajax looks like with jQuery:
app/controllers/static_pages_controller.rb:
class StaticPagesController < ApplicationController
def show_link
end
def upvote
respond_to do |format|
format.json {render json: {"count" => "10"} }
end
end
end
app/views/static_pages/show_link.html:
<div>Here is an ajax link:</div>
<%= link_to(
"Click me",
'/static_pages/upvote',
'remote' => true, #Submit request with ajax, and put text/javascript on front of Accept header
data: { type: :json }) #Put application/json on front of Accept header
%>
<div>Upvotes:</div>
<div id="upvotes">3</div>
<script>
$(document).ready( function() {
$(this).ajaxSuccess( function(event, jqXHR, ajaxInfo, data) {
//var js_obj = JSON.parse(jqXHR.responseText);
//$('#upvotes').html(js_obj["count"]);
//Apparently, the fourth argument to the handler, data,
//already contains the js_obj created from parsing the
//json string contained in the response.
$('#upvotes').html(data["count"]);
});
});
</script>
config/routes.rb:
Test1::Application.routes.draw do
get 'static_pages/show_link'
get 'static_pages/upvote'
...
end
url to enter in browser:
http://localhost:3000/static_pages/show_link
See jquery docs here:
http://api.jquery.com/ajaxSuccess/
Response to comment:
You could also do the following in your controller:
def upvote
#upvotes = 2 #Set an #variable to the number of upvotes
respond_to do |format|
format.js {} #By default renders app/views/static_pages/upvote.js.erb
end
end
Then:
app/views/static_pages/upvote.js.erb:
$('#upvotes').html(<%= #upvotes %>)

Update view with Rails (Ajax)

I have an app of reservations. The thing is that admins can view reservations by date. This is done by an input with has appended datepicker. Each time the user picks a date, the view is updated (that's the idea). However, until now I don't know how to update the view with the new data. This are my methods:
def index
#reserva = Reserva.new
#reservas = Reserva.all.joins(:user).where.not(:user_id => session[:user_id])
#mis_reservas = Reserva.where(:user_id => session[:user_id])
end
def actualizar_por_fecha
if params[:fecha] != nil
#mis_reservas = Reserva.find_by_fecha(params[:fecha])
#reservas = Reserva.find_by_fecha(params[:fecha])
respond_to do |format|
format.html { render 'reservas/index' }
end
end
end
And the CoffeeScript code is the following:
$("input#ver_reservas_fecha").on "change", (e) ->
$.ajax
url: "actualizar_lista_de_reservas_por_fecha"
data:
fecha: $("#ver_reservas_fecha").val()
success: (data) ->
console.log(data)
return
return
Thanks in advance
Refer to this question to know how to create a partial and refresh the div after ajax call.
How do I render partial via ajax in rails3 and jQuery
Also refer to this to understand it a bit more
http://richonrails.com/articles/basic-ajax-in-ruby-on-rails

Resources