Rendering an object passed through Pusher in Rails - javascript

I am trying to implement a realtime chat application.
I'm using pusher to notify server about the button click, and then pass the message object as message to a subscriber. What I need to do is, render that message in other user's chat screen(show.html.erb) dynamically. Here is my cycle:
// MessagesController.rb
def create
conversation = Conversation.find(params[:conversation_id])
message = Message.create(content: params[:content], user_id: params[:user_id])
conversation.messages << message
Pusher['test_channel'].trigger('my_event', {
message: message
})
end
And my subscriber is
// show.html.erb
// some html code
<ul class="chats">
<%= render #messages %>
</ul>
// some html code
<script>
// some js code
var channel = pusher.subscribe('some_channel');
channel.bind('some_event', function(data) {
// What to do here?
});
</script>

This assumes you are using jquery. It's also untested so may have a few bugs/syntax errors.
Ajax method:
JS
channel.bind('some_event', function(data) {
$.ajax({
url:'/messages/'+data.message.id,
success:function(html){ $('.chats').append(html)}
});
});
routes:
match '/messages/:id' => "messages#show_no_layout"
controller:
def show_no_layout
#message = Message.find(params[:id])
render "show", layout: false
end
view(show.html.erb):
<%= *whatever you want in here* %>
ICH(read more) method:
This will of course require adding an extra js file which is why its not my first suggestion.
Template:
<script id = "messageTemplate" type = "text/html">
{{ message.content }}
// plus whatever else you want.
</script>
channel.bind('some_event', function(data) {
messageHtml = ich.messageTemplate(data.message);
$('.chats').append(messageHtml);
});

If you are using JQuery,
channel.bind('some_event', function(data) {
$('.message').text(data.message);
});
See this tutorial.

Related

How to send post request to rails action

I'm new to rails so I don't know if that is the best practice. I'm trying to send user input from index view to the index action using ajax then update the view with user input. I'm not trying to save this input in the database.
The #url always return nil.
NOTE: I try to create a custom action with no luck because it requires a template.
Thanks in advance :)
The index action
def index
#url = params[:option]
end
The index view
<input type="text" id="exampleFormControlInput1">
<p id="resp-result"><%= #url %></p>
<script type="text/javascript">
$(".button").click(function(event){
var userinput = document.getElementById("form").value;
console.log(userinput);
event.preventDefault();
$.ajax({
url:"/responses/",
type: "POST",
data: {option: userinput},
dataType: "text",
success:function(result){
alert("success" + result);
},
error:function(result){
alert("error" + result);
}
});
});
</script>
Yuna you will need to output response in json. lets assume that your ajax script can send data to ruby on rails backend properly.
Try this
at ajax
not this
url:"/responses/",
but
url:"/responses.json",
you can then get result as per
alert("success" + result.myurl);
you can myurl as part of the json response
Finally try this
def index
respond_to do |format|
##url = params[:option]
#url='nancy more url'
format.json do
render json: {myurl: #url}.to_json
end
end
end

Rails + JS + Ajax request

Hi I'm making simple clone of game where is Waldo (Wally) with Rails + JS + Ajax. The idea is: player becomes 3 images and has to check where 3 characters (Waldo,Wilma,Wizard) are. After 3. image shows up field to submit name and after submit show high score list.
So far, i have code the mechanism for time (JS variable with setInterval), points (JS + AJAX + rails controller) but i can't code the action for submit name, points and time to model.
My view file:
<%= form_tag('/check/highscore', method: :post, format: :js, remote: true ) do %>
<%= text_field_tag 'name', 'enter your name' %>
<%= submit_tag 'submit' %>
<% end %>
<script type="text/javascript">
$.ajax({
url: "<%= highscore_check_index_path %>",
type: "POST",
format: "js",
dataType: "script",
data: { username: $(this).username, score: guessd, time: time },
success: function(data) {
$('send_highscore').append('data.username')
window.waldo.HS()
},
});
};
my controller file:
def highscore
#username = params[:name]
respond_to do |format|
format.js { render :layout => false }
format.html
end
end
def highscore2
record = Highscore.new
record.username = params[:username]
record.score = params[:score]
record.time = params[:time]
record.save
end
my highscore.js.erb
console.log("<%=j #username %>");
window.waldo.HS = function(username) {
$.ajax({
url: "<%= highscore2_check_index_path %>",
type: "POST",
format: "js",
data: { username: name, score: guessd, time: time },
success: function(data) {
console.log(data);
$('send_highscore').append('data.username')
}
});
});
I know, my oode is very bad quality, but i try to learn it now. Problem is that the highscore.js.erb is not executed although i see it in firebug rendered as a js script file.
The idea of highscore.js.erb is to mix ruby and js variables and together sent do highscore2 action in check controller and save to db.
js.erb is a bad way to learn.
Ruby on Rails can be used as a kind of poor mans Single Page Architecture by using remote: true and returning JS.erb responses. But all it really does it gives you enough rope to hang yourself.
Its a really bad way to learn ajax as it leads to poor code organisation and a very non RESTful application as it leads to a focus on procedures instead of resources.
I instead encourage you to try to learn ajax without mixing ERB and JS. Mixing server side and client side logic just makes everything much more complicated as you have to keep track of what is happening where.
Instead you might want to focus on setting up reusable javascript functions in app/assets/javascripts and fetching JSON data instead of javascript procedures.
This will teach you not only to do ajax in Rails but also how to do it with external API's and teach you valuable lessons about how to structure and organise code.
So lets start looking at how to refactor:
Highscores should be a resource.
Lets start by setting up the routes:
resources :highscores, only: [:create, :index, :show]
And the controller:
class HighscoresController < ApplicationController
respond_to :json, :html
def create
#highscore = Highscore.create(highscore_params)
respond_with #highscore
end
def index
#highscores = Highscore.order(score: :desc).all
respond_with #highscores
end
def show
#highscore = Highscore.find(params[:id])
respond_with #highscore
end
private
def highscore_params
params.require(:highscore).permit(:username, :time, :score)
end
end
Responders is a pretty awesome tool that makes it so that we don't have to do a bunch of boilerplate code when it comes to returning responses. Our create method will return 200 OK if it was successful and 422 BAD ENTITY or some other "bad" response code if it failed.
Some javascript scaffolding
Lets set up a little bit of scaffolding so that we can hook our javascript up to a specific controller and action without using inline script tags.
Open up layouts/application.html.erb and replace the <body> tag:
<%= content_tag :body, data: { action: action_name, controller: controller_name } do %>
<%= yield %>
<% end %>
Then add this little piece to applicaiton.js:
// Triggers events based on the current controller and action.
// Example:
// given the controller UsersController and the action index
// users:loaded
// users.index:loaded
$(document).on('page:change', function(){
var data = $('body').data();
$(this).trigger(data.controller + ":loaded")
.trigger(data.controller + "." + data.action + ":loaded");
});
Where is that ajax y'all was talkin' bout?
Lets say we have a list of highscores that we want to update either at regular intervals (polling) or when the user submits a highscore.
// app/assets/javascripts/highscores.js
function getHighscores(){
var $self = $('.highscores-list');
return $.getJSON('/highscores').done(function(highscores){
var elements = $.map(highscores, function(h){
return $('<li>').text([h.username, h.score].join(', '));
});
$self.empty().append(elements);
});
};
$(document).on('games:loaded highscores:loaded', function(){
// refresh highscores every 5 seconds
(function refresh(){
getHighscores().done(function(){
window.setTimeout(refresh, 5000);
});
}());
});
That last part is a bit hairy - its a recursive function that sets a new timer when the ajax call has completed. The reason we use this and not setInterval is that setInterval does not care if the previous call was completed or not.
Creating Highscores.
First lets russle up a form:
<%# app/views/highscores/_form.html.erb %>
<%= form_for(local_assigns[:highscore] || Highscore.new), class: 'highscore-form' do |f| %>
<div class="field">
<%= f.label :username %>
<%= f.text_field :username %>
</div>
<%= f.hidden_field :score %>
<%= f.hidden_field :time %>
<%= f.submit %>
<% end %>
And then lets spiff it up with some ajax goodness:
$(document).on('games:loaded highscores:loaded', function(){
$('#new_highscore').submit(function(e){
$.ajax(this.action, {
data: {
highscore: {
username: this.elements["highscore[username]"].value,
time: this.elements["highscore[time]"].value,
score: this.elements["highscore[score]"].value
}
},
method: 'POST',
dataType: 'JSON'
}).done(function(data, status, jqXHR){
getHighscores();
// todo notify user
});
return false; // prevent form from being submitted normally
});
});

Using AJAX POST from javascript to Rails 4 controller with Strong parameter

I'm newbie with Rails
My purpose is insert song_id and title which received from Javascript via AJAX POST into Database (MySQL)
In my javascript file
var song_id = "23f4";
var title = "test";
$( document ).ready( function() {
jQuery.ajax({
url: 'create',
data: "song_id=" + song_id + "&title=" + title,
type: "POST",
success: function(data) {
alert("Successful");
},
failure: function() {
alert("Unsuccessful");
}
});
} );
In my editor_controller.rb
class EditorController < ApplicationController
def new
#song = Song.new
end
def create
logger.debug("#{params[:song_id]}")
logger.debug("#{params[:title]}")
#song = Song.new(song_params)
if #song.save
redirect_to root_path
else
flash[:notice_song_failed] = true
redirect_to root_path
end
end
private
def song_params
params.require(:song).permit(:song_id, :title)
end
The problem is when I running the Rails app with this code, the Console notices me that
ActionController::ParameterMissing at /editor/create
param is missing or the value is empty: song
I'm trying to use
private
def song_params
params.require(:song).permit(params[:song_id], params[:title])
end
but it doesn't work and notices me the same, moreover in the terminal log told me below
Started POST "/editor/create" for ::1 at 2015-04-01 01:07:23 +0700
Processing by EditorController#create as /
Parameters: {"song_id"=>"23f4", "title"=>"test"}
23f4
test
Completed 400 Bad Request in 1ms
Do I missed something in my code, Thanks for Advance.
You are not sending a song parameter at all. It looks like you need to update the data line in the jQuery.ajax call to include the song parameter like so:
data: {song: {song_id: song_id, title: title}}
This:
params.require(:song).permit(params[:song_id], params[:title])
is saying "require the 'song' parameter, and allow 'song_id' and 'title' through. If you don't pass a song parameter, you'll get a bad request.
You can either:
Change that line of code to remove the require on 'song'
or
Like #infused says, change your ajax call to send a song JSON object.

rails 4.0.1 can't show ruby code in view via javascript ajax

I'm trying to update vote count via ajax once user has voted. My code works fine except for something which should be pretty basic, which is showing the new total number of votes.
My javascript has the following code:
var voteCount = "<%= #trip.total_up_votes %>";
...
$.ajax({
...
success: function() {
console.log("SAVED TO VOTES TABLE SUCCESSFULLY");
$('#voting_up').html(voteCount);
},
...
});
Once the vote link has been clicked, everything gets added to the table fine except it shows the new vote count as <%= #trip.total_up_votes %> i.e. as a string. The total_up_votes method simply counts the number of up votes from the votes table. This works fine when the page is first loaded or when it's refreshed.
I've tried escape_javascript and many other suggestions after trawling through the internet but I'm still stuck. Could someone help please?
EDIT:
As requested, my votes_controller does this:
def cast_vote()
#vote = Vote.where("user_id = ? AND trip_id = ?", current_user, params[:id]).first || Vote.new(:user_id => current_user)
#vote.vote_type = params[:vote_type]
#vote.user_id = params[:user_id]
#vote.trip_id = params[:id]
respond_to do |format|
#vote.save
format.html {redirect_to :back}
format.js
end
end
Have you tried dropping the quotes?
var voteCount = <%= #trip.total_up_votes %>;
...
$.ajax({
...
success: function() {
console.log("SAVED TO VOTES TABLE SUCCESSFULLY");
$('#voting_up').html(voteCount);
},
...
});
This is all overkill. You should use the ruby ajax helper "remote". use this:
<%= link_to "Vote up", vote_up_path, remote: true %>
The remote: true above will tell the browser to handle the link via ajax, so the page will not get reloaded. vote_up_path is just an example. Lets say vote_up_path takes you to the controller action votes#upvote, then in your votes views folder you should have a file called upvote.js.erb. In that file, have the following code:
var voteCount = <%= #trip.total_up_votes %>;
console.log("SAVED TO VOTES TABLE SUCCESSFULLY");
$('#voting_up').html(voteCount);

Using infinite scroll in a Rails application

I want my application to have an endless scroll. For that I'm using this javascript https://github.com/jney/jquery.pageless/blob/master/lib/jquery.pageless.js
Then as he suggested in the usage I wrote added the pageless function in my script tag. But the application is failing to work. Am I doing this correctly?
<div id = "container1"></div>
<script>
$(document).ready(function() {
$.ajax({
url : "shirts/first",
type : "GET"
});
$("#name").autocomplete({
source : "shirts/autocomplete",
autoFocus : false,
minLength : 1,
select : function(event, ui) {
document.getElementById("name").value = ui.item.value;
$.ajax({
url : "shirts/show?name=" + ui.item.value,
type : "GET"
});
}
});
$('#container1').pageless({
totalPages: 4,
url: 'shirts/first',
loaderMsg: 'Loading more results'
});
});
</script>
Controller code:
def first
#init = Sunspot.search(Clothes) do
paginate :page => params[:page], :per_page => 16
order_by :maxprice
end
#first = #init.results
if request.xhr?
sleep(1)
render :partial => 'shirts/first', :collection => #first
end
end
first error i see is that you have defined the div with id #container1 but your jquery calls #container
also make sure you have the proper urls loading in that js. if this doesn't work, please provide more info

Categories

Resources