I want to create a simple twitter_clone. Now I'm trying to add a feature to be able to unfollow a user.
What I've done until now:
User can follow other user (I did it through Flux pattern)
I've done it this way:
followUser(userId){
$.post("/followers", {user_id: userId})
.success(rawFollower => ServerActions.receivedOneFollower(rawFollower))
.error(error => console.log(error));
},
It sends a POST to /followers and a USER STORE is fetching this data to update itself.
Now I'm looking for the way how to delete it. I've tried to do it by:
unfollowUser(userId){
console.log ("API.unfollowUser");
$.delete("/followers", {user_id: userId})
.success(unfollowUser => ServerActions.removedOneFollower(unfollowUser))
.error(error => console.log(error));
}
but it doesn't work. I've received an error:
Uncaught TypeError: $.delete is not a function
Basically, I try to remove one row from database and accordingly json connected with it and Later to update a STORE (delete this json from array which I use to determine a state of React Element)
This is destroy action from Rails followers controller:
def destroy
follower = Follower.find(user_id: params[:user_id],
followed_by: current_user.id)
follower.destroy
end
Could someone help me?
As you can see, the error you're getting is a Javascript error, not a Rails error.
There's no $.delete method for jQuery. Instead, you have to use the $.ajax one and specify the HTTP method, like so:
$.ajax({
url: '/followers',
method: 'DELETE',
data: { user_id: userId }
}).done(unfollowUser => ServerActions.removedOneFollower(unfollowUser))
.fail(error => console.log(error))
However, this might also fail because jQuery may not support sending data with a DELETE request, and that makes sense.
If you're using Rails and trying to be RESTful, you shouldn't be sending a DELETE request like this:
DELETE /followers
{ user_id: userId }
Rather, you should send a DELETE request like this:
DELETE /followers/:user_id
So to modify the code, it becomes like this:
$.ajax({
url: '/followers/' + userId ,
method: 'DELETE',
}).done(unfollowUser => ServerActions.removedOneFollower(unfollowUser))
.fail(error => console.log(error))
I haven't tried any of the code above, but It Should Just Work (TM).
Related
So I am building a react on rails project to learn some new things. I am trying to use the fetch API to get data from the db.
I have tried this method and this one. But I might be implementing them wrong.
This is my fetch route:
fetch('/get_data')
.then(response => {
response.json();
})
.then(data => console.log(data));
I have my route set up in Ruby on Rails:
match '/get_data' => 'get_data#pull', via: :get
I have my controller just doing something simple at the moment to see if I can get any data.
class GetDataController < ApplicationController
def pull
#allproduct = Product.all
render json: #allproduct
end
end
Thanks for any help in pointing me in the right direction!
The issue was that I needed a return statement in my fetch call. :)
fetch('/get_data')
.then(response => {
return response.json();
})
.then(data => console.log(data));
I've rewritten my question to be more accurate. I have a bankaccounts controller / model.
I have the following method on my controller
def search
##ledgeritems = Ledgeritem.where("bankaccount_id = ? and transactiondate >= ? and transactiondate < ?", params[:bankaccount_id], params[:startdate], params[:enddate])
#bankaccount = Bankaccount.find(params[:bankaccount_id])
respond_to do |format|
format.js { render :partial => "bankaccount/bankledger" }
end
end
I've made two attempts to call this.
Attempt 1
Route for attempt 1
resources :bankaccounts do
post "search"
end
This shows the following route when I do a rake
bankaccount_search POST /bankaccounts/:bankaccount_id/search(.:format) bankaccounts#search
Javascript for calling attempt 1
$.ajax({
type: "POST",
url: "/bankaccounts/" + bank_account_id + "/search.js",
data: $('#edit_bankaccount_' + bank_account_id).serialize(),
success: function (result, status) {
$('#bank_ledger_div').html(result);
}
});
This calls the correct route on my controller, but the server sees it as a PUT instead of a POST and returns a 404.
Attempt 2
Route for attempt 2
resources :bankaccounts do
collection do
post "search"
end
end
This shows the following route when I do a rake
search_bankaccounts POST /bankaccounts/search(.:format) bankaccounts#search
Javascript for calling attempt 2
$.ajax({
type: "POST",
url: "/bankaccounts/search.js",
data: $('#edit_bankaccount_' + bank_account_id).serialize(),
success: function (result, status) {
$('#bank_ledger_div').html(result);
}
});
This calls the update route but still showing as a PUT command. In Firebug I see a 500 error with the following result
Couldn't find Bankaccount with id=search
Usually this error means you're making a GET request instead of a POST request.
For example:
GET /bankaccounts/search is assumed to be requesting the SHOW page for a bankaccount with ID = search
While
POST /bankaccounts/search would correctly hit your action.
Edit:
resources :bankaccounts do
collection do
post "search"
end
end
Is correct as well. Now I'm noticing that you are doing this to get your data:
data: $('#edit_bankaccount_' + bank_account_id).serialize()
that form likely has a hidden field in it, put there by rails, with name='_method' and value='PUT'. That is what is convincing rails that your POST is really a PUT. You'll need to remove that from the serialized data in order to correctly post the form.
If you want the /search url to be used without specifying an id, you should declare it as a collection action :
resources :bankaccounts do
collection do
post "search"
end
end
You can check the routes defined in your app with the rake routes command, to ensure that you defined what you meant.
The URL is expecting the format
/bankaccounts/:bankaccount_id/search
Is the error coming from this method? Could /bankaccounts/search be matching another route?
In a non-AJAX web app, the URL would contain my view parameters (e.g. mysite?page=2&sort=name). In an AJAX app, where do I store the same info? In the Session object?
I'm assuming you want to know how to pass additional params with an AJAX call. This really depends on how you're formulating the AJAX call.
If you're using the built-in Rails helpers, you can pass additional params inside the url_for helper. For example, lets say that you have a products route and you want to AJAX load a list of all products. The link_to helper might look something like this (Rails 3.2)
link_to "All Products", products_path(:page => 2, :sort => "name"), :remote => true
If on the other hand you're using a JavaScript framework like jQuery, you can pass additional params using the data option. For example
$.ajax({
url: "/products",
data: {
page: 2,
sort: "name"
},
success: function(data) {
// handle success
},
failure: function(data) {
// handle failure
}
});
Storing this data (page, sort, etc.) can be done multiple ways also. The easiest way would be to store this data inside a JavaScript variable.
window.page = 2;
window.sort = "name";
Another solution is to store this information in the data attribute of a particular DOM element on the page. For example, if you have a <div id='products'> that contains a list of the paginated, sorted products, you could store the information like this (jQuery)
$("#products").data("page", 2);
$("#products").data("sort", "name");
Generally speaking, you don't structure you're requests differently for AJAX in Rails. You'll just add the :remote => true attribute to your link or form, then make the controller action respond_to js
respond_to do |format|
format.js
end
And then put your_action.js.erb in your views and write javascript that updates the dom in the appropriate way.
I'm trying to implement something similar to http://pusher-chat.heroku.com/
However, I cannot figure out how to call an action without the page refreshing.
The page refreshing defeats the purpose of using pusher.
So far I have created a chat table, with attributes account_id and message.
In my chat controller I have the following:
def create
account = Account.getAccountById(session[:user])
if params[:message].blank?
#title = "Chat"
#chatLog = Chat.find(
:all,
:order => "created_at ASC",
:limit => 20
)
render :action => :index
else
chatter = Chat.new(
:account_id => account.id,
:message => params[:message]
)
payload = {
"account_id" => chatter.account_id,
"message" => chatter.message
}
if chatter.save
Pusher['chat-channel'].trigger('send_message', payload)
#title = "Chat"
#chatLog = Chat.find(
:all,
:order => "created_at ASC",
:limit => 20
)
render :action => :index
else
render :action => :index
end
end
rescue ActiveRecord::RecordNotFound
reset_session
redirect_to(new_account_path)
end
In my chat.js file I have the following:
$(document).ready(function() {
// Enable pusher logging - don't include this in production
Pusher.log = function(message) {
if (window.console && window.console.log) window.console.log(message);
};
// Flash fallback logging - don't include this in production
WEB_SOCKET_DEBUG = true;
var pusher = new Pusher('62651eca256339fa7fca');
var channel = pusher.subscribe('chat-channel');
channel.bind('send_message', function(chatter) {
$('#loading').show();
});
});
I've never built anything like this before, so I would appreciate any help.
I know there has to be a lot more javascript involved.
Thank you,
Brian
To call an action without refreshing you should use ajax.
I haven't tried pusher yet but it seems that whenever someone "submits" a new message, your application, it shall send to the pusher channel so it can broadcast to every "subscribed" client online.
If this is correct, you should think the whole thing as this:
When someone clicks on "new chat" it will create a new chat room, instantiate a new channel on pusher and save it on database. This will generate the identification on the url, that you can send to someone so that they can join your chat.
On the chat screen, you will have one big div that will render the chat and on input text field where you send messages. This particular field will submit to your application using ajax your chat ID and the message.
On your chat controller when you receive this information, you go get the pusher channel id on database for that chat room, save message on database for history and send it back to every user connected on that room with pusher.
The logic to render the text on the chat will be done by client side javascript.
Hmmh, my approach would be to use a Javascript timer which calls an AJAX-script every two seconds to get the new chat entries since the last request - and then refresh only the chatbox. Like so:
var latest_entry_number = 0;
var chatter = window.setInterval("getNewestEntries()",2000);
function getNewestEntries() {
$.ajax({
url: "/path/to/latest_entries",
type: "POST",
dataType: "JSON",
data: {latest_entry: latest_entry_number}
success: appendEntries
});
}
function appendEntries(data) {
latest_entry_number = data.latest_entry;
$.each(data.entries, function(key,val){
//append the entries to the chat
})
}
And the controller action would look like this:
def latest_entries
data[:latest_entry] = get_latest_entry # each entry gets a consecutive, ascending number
data[:entries] = get_entries_since(params[:latest_entry_number]) # get all entries done since that number
# Should be an array
render :json => data
end
Or something like that.
I'm building a simple tasks application for our company as part of an ordering system.
I have a list of tasks with a number of rules. Nothing complex... What I'm stuck on is the addition of a checkbox to complete the task. I want it done live, from the index view without having to hit submit..
Am really not sure even where to look. I figure I need to use ajax to do this - can anyone recommend a tutorial or tell me what I should be looking for.
Have also thought about a plugin, like the edit in place ones out there.
Thanks in advance
--- EDIT 1 --
Following advice from #pcg79 below, I've added the following to my application but am not understanding how I go out actually changing the status.
In my index view I have this:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(#task) } %><
I've added the following to my application.js (added a # to get it to call properly)
$('#complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
For lack of understanding, I added this to my tasks controller:
def completed
#task = Task.find(params[:id])
#task.status = true
end
Which seemed reasonable but wasn't sure how to actually call that in the ajax?
In my development log I can see it sort of working but it says this:
ActionController::RoutingError (No route matches "/tasks"):
-- EDIT 2 --
As per advice from #jdc below, I've tried adding the following to routes.rb:
get 'tasks/:id/completed' => 'tasks#completed', :as => :completed_task
But still get the RoutingError.
-- Slight Update --
Following the excellent advise from #pcg79 below, I've updated my files with the following.
Routes.rb
get 'task/:id' => 'tasks#completed', :as => :completed_task
Index.html.erb
<td><%= check_box_tag 'complete_task_1', '', false, { 'data-href' => completed_task_path(:id => task.id) } %></td>
Tasks controller
def completed
#task = Task.find(params[:id])
#task.status = true
#task.save
end
I get no errors in my browser, but my development log shows this:
ActionController::RoutingError (No route matches "/tasks"):
For a simple checkbox, this is hard work!!!
-- Another update --
Having played all day, I decided to see what would happen with a button_to instead, forgetting the ajax side of things. I put this in my code:
<%= button_to "Complete", completed_task_path(task.id) %>
And changed routes to:
match 'tasks/:id/completed' => 'tasks#completed', :as => :completed_task
Which worked a treat. Changing back to check_box_tag breaks it all again :(
Pretty much worked out it's the contents of my function. Having removed some code, I can update the css for a #:
$('#complete_task_1').click(function() {
$.ajax({
success: function(data, textStatus, jqXHR) {
$('#thing').css("color","red");
}
});
});
Any idea what I'd need to call my action?? J
If I understand what you're looking for (when the checkbox is checked or unchecked an Ajax request is sent to the server and the associated object is saved with the result of the checkbox), then yes you'll want to do it in Ajax.
With Rails 3 you're probably using jQuery (or, IMO, you should be). You'll need to implement a click event on the checkbox element. That click event, when it's fired, will do an Ajax call to your server. You'll want to do a PUT request since it's an update. You'll send the id of the object and the value of the checkbox.
There are a decent amount of sites that have examples of Rails and Ajax. This one (http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3/) is good as it has you use the HTML 5 "data" fields which I like. There's also a bunch of similar questions here on SO. Here's one that's not Rails but will give you an idea of how to write the jQuery (AJAX Checkboxes).
Edit to answer question in comment
The checkbox can be wherever you want it since you're doing Ajax. If you want it on your index view, that's where you put it. Your checkbox will look something like this (please understand I'm not double checking my syntax or anything):
= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(#task_1) }
Then your jQuery will look something like:
$('complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
Second edit: I realized I forgot to actually send the value of the checkbox in the Ajax. You can do that and just call #task.update_attributes or you can make the url a specific method that only completes tasks.
Edit for updated question:
To explain my second edit, in order to update the task to be completed, you can do one of two things. You can either call a method that is expressly for setting the status attribute. Or you can call your normal, RESTful update method passing in :task => {:status => true} and call #task.update_attributes(params[:task]). You've chosen to do the former which, IMO, is fine.
So you have two problems. The first is that you aren't referencing the new route which points to your completed method. The second is that you aren't saving your object in the completed method.
To fix the first problem, you need to change the path your data-href attribute in the check_box_tag method points to. You don't want task_path. IIRC, you'll want completed_task_path(#task). The easiest way to find out the name of the path is to run rake routes in your Rails project's root directory.
To fix the second problem, just make sure to call #task.save at the end.
def completed
#task = Task.find(params[:id])
#task.status = true
#task.save
end
In your updated example, try replacing:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(#task) } %>
with:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(#task) } %>
Provided #task.id = 1, tasks_path(#task) returns /tasks.1, while task_path(#task) returns /tasks/1