Good day,
I would like to create a real time Newsticker/Marquee scroller for my rails app, Similar to what you would find on Sky Sports News TV channel.
I Need to be able to query the database table (which i can) and display the output in the ticker/marquee one table row at a time looping it over. Also i would like to either try display this query in real-time or very frequently and updating the output on the clients end without the page refreshing. (Similar to a chat room or twitter feed.)
Here is some basic code
Simple Query Which shows the subject and paper if the start time is < Current time and Stop time is > Current time
Model
Timetable.where("start < ? AND stop > ?", Time.now, Time.now).order('id ASC').pluck(:subject, :paper)
Html
<table><tbody><% #timetables.each do |timetable| %><tr><td><%= timetable[0] %></td><td>%= timetable[1] %></td></tr><% end %></tbody></table>
If anyone is able to hepl or point me in the right direction, Ill really appreciate it. Thanks
At the moment i could probably use a partial to display the query and update the partial, not sure if there is a better method using any gems that will open up an event listener or socket?
Interesting problem you've got here. Got me excited and I tried some things out myself!
If you want to have content refreshed on the client side (no page reload), you need to use javascript to repeatedly query the server. In Rails you'd probably go with a partial that's being rendered from both the page view and the API-view that's used in an AJAX call.
Let's assume you have a model called Item of which you want to show the latest 3 on your page and then fetch the latest every 5 seconds to update the page. You might want to create something that looks like the following:
controllers/content_controller.rb
class ContentController < ApplicationController
def show
end
end
views/content/show.haml
%h1 Page with updated items
.updateme
= render "items/latest"
controllers/items_controller.rb
class ItemsController < ApplicationController
layout false
def index
end
end
views/items/index.haml
= render "items/latest"
views/items/_latest.haml
- Item.last(3).each do |item|
= item.subject
Last but not least you will need to add javascript that calls the index for items
javascripts/update.js
function updateItems() {
$.ajax({
url: "/items",
}).done(function(data) {
$("div.updateme").html(data)
});
}
$( document ).ready(function() {
window.setInterval(function(){
updateItems();
}, 5000);
});
Hopefully this gets you started in the right direction :)
Related
Im using AngularFire+Firebase and have data at firebase-database.
Im trying to paginate Data with Smart Table
My problem is that I dont know how to range query without specifying any child i,e fetch records from record # 25 to 35
Below query gives me first 5 records
var queryFIrst = visitRef.startAt().limitToFirst(5);
$scope.Visits = $firebaseArray(queryFIrst);
now Im trying to get records next 5,from 6 to 10 and I tried below
var queryFIrst = visitRef.startAt().limitToFirst(5).endAt().limitToFirst(5);
$scope.Visits = $firebaseArray(queryFIrst);
but it giving error that startAt and endAt can't be used like this with limit
In general pagination is not a good fit for Firebase's realtime data model/API. You're trying to model a SQL SKIP operator, which won't work with the Firebase Database.
But if you want to model pagination in Firebase, you should think of having an "anchor point".
When you've loaded the first page, the last item on that page becomes the anchor point. When you then want to load the next page, you create a query that starts at the anchor point and load n+1 item.
In pseudo-code (it's real JavaScript, I just didn't run it):
var page1 = visitRef.orderByKey().limitToFirst(5);
var anchorKey;
page1.on('child_added', function(snapshot) {
anchorKey = snapshot.key; // this will always be the last child_added we received
});
Now when you want to load the next page of items, you create a new query that starts at the anchor key:
var page2 = visitRef.orderByKey().startAt(anchorKey).limitToFirst(6);
A few things to note here:
You seem to be using an approach from the Firebase 1.x SDK, such as an empty startAt(). While that code may still work, my snippets use the syntax/idiom for the 3.x SDK.
For the second page you'll need to load one extra item, since the anchor item is loaded for both pages.
If you want to be able to paginate back, you'll also need the anchor key at the start of the page.
Is that what you needed that time?
visitRef.orderByKey().startAt("25").endAt("35")
I asked a similar question Get specific range of Firebase Database children
I am trying to notify the browser of the user of a change of the status of the model. I am trying to use the live-module of Rails for that. Here is what I have got so far:
require 'json'
class Admin::NotificationsController < ActionController::Base
include ActionController::Live
def index
puts "sending message"
videos = Video.all
response.headers['Content-Type'] = 'text/event-stream'
begin
if(params[:id].present?)
response.stream.write(sse({id: params[:id]},{event: "video_encoded"}))
end
rescue IOError
ensure
response.stream.close
end
end
private
def sse(object, options = {})
(options.map{|k,v| "#{k}: #{v}" } << "data: #{JSON.dump object}").join("\n") + "\n\n"
end
end
The idea behind the above controller is, that when its url gets called with a parameter, it would send this parameter (in this case the id) to the user. Here is how I am trying to call the controller:
notifications_path(id: video.id)
Unfortunately though, the following event-listener in the browser does not fire, even if I use curl to provoke an event:
var source = new EventSource('/notifications');
source.addEventListener("video_encoded", function(event) {
console.log("message")
console.log(event)
});
The goal of this is, that I want to add an dom-element to a certain page (later on) if there is a change. There may be a better way, but Ruby Live seemed like a suitable solution. Any tips or proposals of a different approach are appreciated.
Your use case does not seem like a valid use case for ActionController::Live. You are not sending a streaming output to the browser. You do a one time check on ID and send the JSON output.
Use a regular controller and get the request by AJAX instead of EventSource.
I am attempting to follow this tutorial and I am getting stuck: Adding a 5 star ratings feature to a Rails 4 model.
Im a begginer with javascript and ajax so I spent a few hours learning how ajax works with javascript. I believe the problem has to do with where the average_rating method is (rails problem?).
def average_rating
ratings.sum(:score) / ratings.size
end
Currently I have followed the tutorial exactly how it says, while replacing comment with review. In the tutorial it says to define the average_rating in the comment model (mine is in the review model), and I am not sure why I would do that.
Also I have added this (not sure if It belongs in the current controller or if it belongs in rating controller):
#this is the controller used for the view which displays the stars
def page
#rating = Rating.where(review_id: #review.id, user_id: #current_user.id).first
unless #rating
#rating = Rating.create(review_id: #review.id, user_id: #current_user.id, score: 0)
end
end
When I try to load the page here is the error I get: ZeroDivisionError below it says divided by 0 and it highlights this line score: <%= #review.average_rating %>,
UPDATE When I delete this script from the view which has the average_rating, the stars show for my_rating. So something is messing up with the average part:
<script> #did not delete this line
$('#star').raty({
readOnly: true,
score: <%= #review.average_rating %>,
path: '/assets'
});
Deleted part^^^
Basically, i would love to get more info, but here are some pointers that might help:
make sure the relation is working: make sure you have has_many :ratings for the user/review and 'belongs_to :user/:review' for the ratings. other direction- are you getting the ratings in a controller method? if so, consider changing it to #ratings.
use first_or_XXXX - this is a great rails option to save conditional instantiation. there is first_or_create that would do exactly what you did:
Rating.where(review_id: #review.id, user_id: #current_user.id).first_or_create do |rating|
rating.score = 0
end
finally, ratings.size, will not update after create, which might explain the zero devision. read more in this question's selected answer and comments. Therefore, it's recommended to use count (will check on the db, so only saved ratings will be counted) or length (i.e. user/review.ratings.length which will count also built (not saved) objects.
hope that helps.
I'm trying to display a progress bar during mass mailing process. I use classic ASP, disabled content compression too. I simply update the size of an element which one mimics as progress bar and a text element as percent value.
However during the page load it seems Javascript ignored. I only see the hourglass for a long time then the progress bar with %100. If I make alerts between updates Chrome & IE9 refresh the modified values as what I expect.
Is there any other Javascript command to replace alert() to help updating the actual values? alert() command magically lets browser render the content immediately.
Thanks!
... Loop for ASP mail send code
If percent <> current Then
current = percent
%>
<script type="text/javascript">
//alert(<%=percent%>);
document.getElementById('remain').innerText='%<%=percent%>';
document.getElementById('progress').style.width='<%=percent%>%';
document.getElementById('success').innerText='<%=success%>';
</script>
<%
End If
... Loop end
These are the screenshots if I use alert() in the code: As you see it works but the user should click OK many times.
First step is writing the current progress into a Session variable when it changes:
Session("percent") = percent
Second step is building a simple mechanism that will output that value to browser when requested:
If Request("getpercent")="1" Then
Response.Clear()
Response.Write(Session("percent"))
Response.End()
End If
And finally you need to read the percentage with JavaScript using timer. This is best done with jQuery as pure JavaScript AJAX is a big headache. After you add reference to the jQuery library, have such code:
var timer = window.setTimeout(CheckPercentage, 100);
function CheckPercentage() {
$.get("?getpercent=1", function(data) {
timer = window.setTimeout(CheckPercentage, 100);
var percentage = parseInt(data, 10);
if (isNaN(percentage)) {
$("#remain").text("Invalid response: " + data);
}
else {
$("#remain").text(percentage + "%");
if (percentage >= 100) {
//done!
window.clearTimeout(timer);
}
}
});
}
Holding respond untill your complete processing is done is not a viable option, just imagine 30 people accessing the same page, you will have 30 persistent connections to the server for a long time, especially with IIS, i am sure its not a viable option, it might work well in your development environment but when you move production and more people start accessing page your server might go down.
i wish you look into the following
Do the processing on the background on the server and do not hold the response for a long time
Try to write a windows service which resides on the server and takes care of your mass mailing
if you still insist you do it on the web, try sending one email at a time using ajax, for every ajax request send an email/two
and in your above example without response.flush the browser will also not get the % information.
Well, you don't.
Except for simple effects like printing dots or a sequence of images it won't work safely, and even then buffering could interfere.
My approach would be to have an area which you update using an ajax request every second to a script which reads a log file or emails sent count file or such an entry in the database which is created by the mass mailing process. The mass mailing process would be initiated by ajax as well.
ASP will not write anything to the page until it's fully done processing (unless you do a flush)
Response.Buffer=true
write something
response.flush
write something else
etc
(see example here: http://www.w3schools.com/asp/met_flush.asp)
A better way to do this is to use ajax.
Example here:
http://jquery-howto.blogspot.com/2009/04/display-loading-gif-image-while-loading.html
I didn't like ajax at first, but I love it now.
Hello people
I'm trying to figured this out, but I still can't do it.
I have a rails 3 app, I'm working with invoices and payments. In the form for payments I have a collection_select where I display all the invoices number (extracted from a postgres database), and what I'm trying to do is when i select an invoice autopopulate others text_fields (provider, address, etc.) without reloading the page, in the same form.
I know I should use ajax, js, jquery, but I'm a beginner in these languages, so i don't know how or where to start
hope you can help me... thanks
What you are going to want to do is route an ajax call to a controller, which will respond with json containing the information. you will then use jquery to populate the different fields.
In your routes:
get "invoice/:id/get_json", :controller=>"invoice", :action=>"get_json"
In your invoice_controller:
def get_json
invoice = Invoice.find(params[:invoice_id])
render :text => invoice.to_json
end
In your invoice model (if the default to_json method is not sufficent):
def to_json
json = "{"
json += "id:'#{self.id}'"
json += ",date_created:'#{self.date}'"
... //add other data you want to have here later
json += "}"
end
In your javascript file,
$("#invoice_selecter").change(function(){ //calls this function when the selected value changes
$.get("/invoice/"+$(this).val()+"/get_json",function(data, status, xhr){ //does ajax call to the invoice route we set up above
data = eval(data); //turn the response text into a javascript object
$("#field_1").val(data.date_created); //sets the value of the fields to the data returned
...
});
});
You are probably going to run into a few issues, i would highly recommend downloading and installing fire bug if you are not on google chrome.. and if you are, make sure you are using the development tools. I believe you can open them up by right clicking and hitting inspect element. Through this, you should be able to monitor the ajax request, and whether or not it succeeded and things.