Ruby on Rails 3.0 Pusher Chat - ruby-on-rails

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.

Related

Twilio can't find xml on rails

I am integrating twilio click to call into my rails project.
Everything works fine however the url: in my twilio controller cannot be found on heroku. However, it can be found if you navigate to it in a browser. The phone dials but the voice says "Sorry a problem has occurred, good bye." If I change the url to an external xml file it works fine, just doesn't recognize this particular one. So I'm lead to believe that the controller etc works fine.
twillio_controller.rb
def call
#full_phone = current_user.phone
#partial_phone = #full_phone.last(-1)
#connected_number = "+61" + #partial_phone
#client = Twilio::REST::Client.new ##twilio_sid, ##twilio_token
# Connect an outbound call to the number submitted
#call = #client.calls.create(
:from => ##twilio_number,
:to => #connected_number,
:url => 'http://besttradies.herokuapp.com/mytradies/connect.xml', # Fetch instructions from this URL when the call connects
)
#msg = { :message => 'Phone call incoming!', :status => 'ok' }
end
def connect
# Our response to this request will be an XML document in the "TwiML"
# format. Our Ruby library provides a helper for generating one
# of these documents
response = Twilio::TwiML::Response.new do |r|
r.Say 'If this were a real click to call implementation, you would be connected to an agent at this point.', :voice => 'alice'
end
render text: response.text
end
The OP solved in the comments above:
Figured it out. Routes for connect needed to be POST and I also had to
add skip_before_action :verify_authenticity_token to the twilio
controller as it was behind membership doors.

DELETE request, react + flux + rails

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).

Auto-update text field depending on selected option

Rails ver: 4.0.0
Hi all,
In my form I have a drop-down selection of client names. I would like to have a text box containing the client's address be updated whenever the selection is changed (before clicking the submit button to finalize the update). The reason is I am working with legacy data from another project where there can be several client entries with the same name but different addresses (e.g. large corp with several offices).
Obviously (perhaps?) I can't use any of the client-side script solutions since the new address has to be retrieved from the model - unless there is a way for java/coffee script to do a db lookup that I don't know about (which is highly likely since I only have a superficial acquaintance with them).
Thanks for any hints or pointers.
You can do something like this assuming you have #client:
Add a hidden div to your view to hold a data attribute:
<div id="client_id" style="display:none;" data-client="<%= #client.id %>"></div>
In somefile.js.coffee:
App ||= {}
App.client =
address = $("#id_of_your_select_field")
client = $("#client_id).data('client')
toggler.on 'change', ( e ) ->
App.client.getAddress
getAddress: ->
$ajax(
type: 'post'
url: "/get_address"
client_id: client
success: ( data, status, xhr ) ->
# you could parse JSON here if you want, or keep reading and leave this blank
)
in routes.rb
post '/get_address/:client_id', to: 'clients#return_address'
in clients_controller.rb
def return_address
#client = Client.find(params[:client_id])
respond_to do |format|
format.js
end
end
and in views/clients/return_address.js do:
var clientAddress = $("#the_civ_with_the_address");
clientAddress.html( "<%= j render( :partial => 'clients/address', :locals => { :client => #client } ) %>" );
Then make a partial with the client info at app/views/clients/_address.html.erb

Check username availability using jquery and Ajax in rails

I am using rails with jquery and ajax to check the availability of username. I am using
the following plugin for jquery validation purpose.
https://github.com/posabsolute/jQuery-Validation-Engine
In my controller i am using the following method to check the username availability.
def check_name
name = params[:name]
if name.strip == ""
render :json => { :available => false }
return
end
user = User.find(:first, :conditions => [ "name = ?", name])
if user
render :json => ["name", false , "This name is already taken"]
else
render :json => ["name", true , ""]
end
end
Is this the correct way to write the method? I checked many of the username availability
posts in this forum, but nothing worked out.
I am adding the answer. Sorry for the delay guys.
First credit to the plugin:https://github.com/posabsolute/jQuery-Validation-Engine .
Used the plugin for validations in the application.
In the view, i had
<%= f.username_field :username, :id => 'free-user', :placeholder=>'User Name', :class => "validate[required, ajax[ajaxUserCall]]", "data-prompt-position" => "topLeft:0,9"%>
In the same view, in java script:
<script type="text/javascript">
$(document).ready(function(){
$("#free-user").bind("jqv.field.result", function(event, field, errorFound, prompText){
if(errorFound){
$(".continue").attr("disabled", false); // .continue is a button
} else{
$(".continue").attr("disabled", true);
}
})
});
</script>
In routes.rb i have the following route.
match '/check-user' =>"users#check_user" // creating route for ajax call
In jquery.validationEngine-en.js file i have following:
"ajaxUserCall": {
"url": "/check-user",
// you may want to pass extra data on the ajax call
"alertText": "* This user is already taken",
"alertTextLoad": "* Validating, please wait"
},
In users controller, i have the following method
def check_user
user = params[:fieldValue]
user = User.where("username = ?", username).first
if user.present?
render :json => ["free-user", false , "This User is already taken"]
else
render :json => ["free-user", true , ""]
end
end
To check the Username/Email Availability do the following:
Using the https://github.com/posabsolute/jQuery-Validation-Engine
edit the validationsEngines-en.js file for the AJAX calls, one for the email will look like the following:
"ajaxEmailAvailable": {
"url": "/route_to_send_the_parameters",
// you may want to pass extra data on the ajax call
"alertTextOk": "* This email is available",
"alertText": "* This email is already taken",
"alertTextLoad": "* Validating, please wait"
},
Make sure you configure your routes.rb file to match the route you want to use, the default action with the call is a GET HTTP Request.
Next set up the proper action in your controller to handle the request (I included a helper in the Application Controller so that the input value can be sanitized before queried in the database:
CONTROLLER HANDLING THE REQUEST
def username_availability
scrubb = help.sanitize(params[:fieldValue], :tags => '')
user = User.find_by_email(scrubb)
if user.blank?
render :json => ["INPUT_ID", true , ""]
else
render :json => ["INPUT_ID", false , "This email is already taken"]
end
end
If you are unsure of the proper INPUT ID, watch the server logs for the parameters passed during the call and do a simple copy-paste. By default the request passes the INPUT ID and INPUT VALUE.
To gain access to this helper add the following:
APPLICATION CONTROLLER
def help
Helper.instance
end
class Helper
include Singleton
include ActionView::Helpers::TextHelper
end
Now on the form itself, your input should read as the following:
<%= c.text_field :email, "data-validation-engine"=>"validate[required, custom[email], ajax[ajaxEmailAvailable]]" %>
As per the proper functionality always place the AJAX call as the last validation.
Don't forget to include jquery.js, jquery.validationEngine-en.js, jquery.validationEngine.js and validationEngine.jquery.css in the head of the document [in that order of js] and to call a
<script type="text/javascript">$(function() {$("#FORM_ID").validationEngine();});</script>
If you want to do this for username, just edit the above appropriately.

Tracking SMS conversation using Rails and Twilio

I am using Twilio in my rails 3.1.3 app and I have got everything basically set up, i.e. a controller for sms and xml builders for the views depending on the response. The only thing I can't figure out is how to keep track of the conversation. The Twilio docs are pretty bad for using anything other than PHP to do this. I have tried using the Rails session hash, session[:variable], but it doesn't seem to be saving the session, as I tried redirecting and printing it out and got nothing. Below is the code of the controller.
def receive
# Check for session variable and redirect if necessary
#sms_state = session[:sms_state]
if #sms_state == 'confirmation'
redirect_to 'confirm'
end
if condition
#sms_state = 'confirmation'
session[:sms_state] = #sms_state
render :action => "view.xml.builder", :layout => false
else
#sms_state = 'new_state'
session[:sms_state] = #sms_state
render :action => "error.xml.builder", :layout => false
end
end
# method that should be called after user deals with first part
def confirm
if condition
#sms_state = session[:sms_state] = nil
render :action => "confirm_view.xml.builder", :layout => false
else
#sms_state = 'confirmation'
session[:sms_state] = #sms_state
render :action => "error.xml.builder", :layout => false
end
end
I have now set up a database table to track the current conversation state depending on the phone number contacting my app. The only thing now that I need to do is set an expiration for this conversation, just like a session or cookie. I am not sure how to do this or if its even possible.
This depends on how you define "conversation", but in general, you are better off using some sort of persistance (would recommend database over a file), and build the structure in accordance with your definition of a conversation.
Suppose the conversation is defined as text messages between two 10-digit phone numbers without a time limit, you can setup a db with a sender and recipient attributes, so if you need to output something in a user interface, you can look for sender and recipient phone numbers, and display all messages coming to them or going from them.
SMS is different from a phone call, since you can set cookies for the session of a phone call. SMS is done when either delivered or sent. When you receive an SMS to a phone number or short code, Twilio will make a request to the URL you provided for SMS, and your app can then respond. If you receive another response, it's a brand new request, so you have to construct the notion of "conversation".

Resources