I am creating a web application that allows gamers to find a partner who is on a similar level. I am using Ruby on Rails 5.
In doing so, I created a player model to store gamer data. This player model works as a queue for my matching algorithm to go through and find a match.
One obstacle to this is that the gamer has to keep the browser open while on queue. If a gamer closes our application or internet connection goes off, the gamer must be removed from queue (= destroy the gamer's player model).
I first approached problem by using javascript 'onbeforeload' or 'navigator.offline'. However, this did not work on rails.
Is there any other approach to keep track of gamer's currnet online status?
Link to my project is at my github.
EDIT
I have tried using pusher to check its connection status to delete the model.
pusher.connection.bind('unavailable', function() {
<% puts "unavailable" %>
<% Player.find_by_user_name(current_user.user_name).try(:destroy) %>
});
pusher.connection.bind('disconnected', function() {
<% puts "disconnected" %>
<% Player.find_by_user_name(current_user.user_name).try(:destroy) %>
});
However, it still is deleting only when the page is reloaded. The pusher does not disconnect even after the browser is closed.
Related
I have an app built on Backbone.js and Django that is just something I'm building for practice.
It's a webchat app that let's users post a message and then saves it to a database, all while constantly fetching new data into a collection I have, so it "updates live" with the server.
On a basic level, the front-end application works with a message model to model a user's message, a messages collection to store all of the posts, and a chat view to render the collection in the chat window.
The code I use to constantly fetch new data from the server is:
// This code is inside the `chat` view's `initialize` function,
// so `that` is set to `this` (the `chat` view) higher up in the code.
window.setInterval(function() {
theColl.fetch({
success: function() {
that.render();
}
});
}, 2000);
I have don't have reset: true because I thought that it would be more efficient to just append new messages to the collection as they were retrieved from the server, instead of reloading every model already in it.
Is this an efficient way to run a simple webchat? As the application has to fetch more models, I've noticed that it gets extremely sluggish, and adds a delay to the user input. Here is a photo to show what I think is one problem (p.s. ignore the stupid messages I wrote):
As the server sends back new models and the collection refreshes, I think that my app is initializing old chat models again, because at this point in the application the collection itself only had 25 models inside of it.
Is there something I can do to stop the reinitialization of every model in the database? As you can see, even though there are only 25 unique models in the chat, and in the database, after letting the app run for 2 minutes or so I get models with CIDs up to 460.
Regardless of that, I've noticed that if I flood the server with new messages things go awry, like new messages appear out of place, and the server gets backed up. The latter may be because I'm using the cheapest option on Digital Ocean to host the app, but I'm not sure what the first problem comes from. It may be from my Django app's views.py or the rest of my Backbone code, I'm not really sure how to debug it.
I have followed the faye railscast and I have a working chat app. My problem is that chrome gives a 404 error, javascripts/defaults.js not found. I found that the problem was in my application layout:
<%= javascript_include_tag :defaults, "http://myip/faye/faye.js" %>
I changed that with:
<%= javascript_include_tag "application", "http://myip/faye/faye.js" %>
and the error disappeared but when I am sending through my form the message it creates and broadcasts a duplicate record of the message.
If more information needed plz ask, I am not sure which part of my code to include in the question.
Faye is a obsolete. Try to use native mechanism - SSE (server set events). It is a best technique for Rails 4 and all modern clients.
I have a page that is for booking an appointment and it has some javascript code that selects the earliest time and day when the appointment is available, after which user can click on the button to schedule the appointment.
So in order to test that, I was writing some rspec test like the following,
book_appointment_spec.rb
context "when on the profile page" do
before do
click_linkedin_button
end
it 'book an appointment', :js => true do
click_link "new-appointment"
choose "doctor1"
click_button "Submit and Schedule"
expect(page).to have_content "Congrats!"
end
end
click_linkedin_button is a method definition that just logins a user via linkedin oauth. The problem is that even after setting OmniAuth.config.mock_auth[:linkedin], whenever I set :js => true around it block, it asks me to login via linkedin, http://imgur.com/mYUOxgD
I was wondering if anyone knows how to fix this problem.
Following are other files that might be relevant to this problem.
spec_helper.rb
require 'capybara/webkit/matchers'
Capybara.javascript_driver = :webkit
Gemfile
gem 'capybara-webkit'
gem 'database_cleaner'
gem 'capybara'
As you've discoverd, you can't run part of a test using one driver and part of the test using another. This would be equivalent to saying
Given I login in using Safari.
Then I should be logged in using Firefox.
So your solution is that you have to run your js login code in the test environment to login. This is actually a good thing (you want to test your js login code). If you want to avoid actually connecting to linkedin, every time you run this test, then you need to mock the connection to linkedin. Have a look at VCR (https://github.com/vcr/vcr), this will allow you to record your connection to linkedin, so that in subsequent test runs you don't have to goto linkedin.
Setting js: true in your rspec block is a shortcut to use the javascript-enabled driver for the whole example. So this driver will be available and used during the whole execution or the example, which includes all before/after/around blocks.
To work around this, instead of using js: true, you can manually set which driver to use at the point(s) of your example where you need to.
it {
do_some_stuff_with_default_driver
Capybara.current_driver = :webkit
do_some_stuff_with_webkit
Capybara.current_driver = :selenium
do_some_stuff_with_selenium
}
EDIT
Oops I just read this, so perhaps that solution will not be working. please let me know
Note: switching the driver creates a new session, so you may not be able to switch in the middle of a test.
I solved it by creating an actual linkedin account, put that auth info in the .env and just called fill_in method to fill out email and password field during its callback. And stuck with running a js driver throughout the entire context block.
EDIT: This is of course not the best answer so I am still accepting other answers.
New to programming here. I'm using Rails to create a web app that does reviews, but am having a little trouble figuring out where to start on this one particular part. I'd appreciate any and all help:
Let's say that on my homepage I want to have a top 10 list of restaurants. Beside each place there would be a score. If you were to click on the link to that restaurant, it would bring you to that restaurant's detail page where you can rate a number of different qualities. As users rate the place the score will update. How can I get that score and ranking to be reflected on my main homepage based on how users rate each place? Thinking this might have to be done with some Javascript (or is there a way to do this in Rails?). Thanks!
The pure answer to your question is you need data persistence - a place to centrally store data & render it in the view for the user.
It's funny why you should ask this question in the Ruby on Rails section - this is exactly what this framework is for, and I would question your competency if you didn't consider this
--
Database
Rails uses a central database to store your data. It uses the MVC programming pattern to give you the ability to access that data wherever you require; allowing you to manipulate it as per your requirements:
Without detailing how to make your app from scratch, I'll give you the basic principle you should use:
#config/routes.rb
root "restaurants#index"
resources :restaurants
#app/controllers/restaurants_controller.rb
Class RestaurantsController < ApplicationController
def index
#restaurants = Restaurant.all
end
end
#app/models/restaurant.rb
Class Restaurant < ActiveRecord::Base
has_many :reviews
end
#app/models/review.rb
Class Review < ActiveRecord::Base
belongs_to :restaurant
end
#app/views/restaurants/index.html.erb
<% for restaurant in #restaurants do %>
<%= restaurant.reviews.count %>
<% end %>
--
Recommended Reading
You'll be best reading the Rails beginner guide on how to get this working properly. It's basically what Rails is for ;)
Only javascript is not enough.
When website is loaded in user's browser, all information from database are loaded once, like html files. Even if you'll update your restaurant object using ajax or simple redirect_to :back method, there will be no change on other page or other browser.
To solve it, you could use something like pusher to send events each time when somebody will trigger an event in your app and receive this events on your home page. If functionality of your app isn't complicated, you can use your own push server like faye in your rails app. Here is reference to railscast about using it:
http://railscasts.com/episodes/260-messaging-with-faye?view=similar
Anyway, i prefer to use pusher every time when I need to add some realtime functionality in my app.
http://pusher.com/tutorials
And about voting process, the nice solutions for doing that is:
"twitter/activerecord-reputation-system"
If you don't want to use ajax which will update your voted restaurant page's content, you can add vote method in your controller with redirect_to :back . This instruction will redirect your app to new url and after finish whole method will redirect back to refreshed page with updated voting status.
def vote
value = params[:type] == "up" ? 1 : -1
#haiku = Haiku.find(params[:id])
#haiku.add_or_update_evaluation(:votes, value, current_user)
redirect_to :back, notice: "Thank you for voting!"
end
To refresh home page dynamically when other users will vote on restaurants, u should create a rake task which will update the information on the page based on updated database structure.
i have some scripts which i have to execute from my ruby on rails application. To ensure that scripts do what they should, my application must show/tail the content of logfiles which where generated from the scripts.
In more detail: i have expect scripts which configure some blackbox devices over a seriell connection (some sort of a rollout mechanism). So i have to watch, for example, a update process or a reboot of the connected device (to verify that everything is okay). This is what i write to my logfiles.
Therefore i need to:
execute a process and handle the exit code
tail a/some logfiles (maybe Javascript or html5?)
How could i do that? Examples will be really appreciate!
Thanks a lot!
The answer to #1 is pretty easy, the system call, i.e.
ret = system('ls','-l')
ret will be true if the command had a zero exit status. $? will contain a Process::Status object from which you can obtain the exit status
unless system('ls','-l','/a_bogus_dir')
logger.debug("ls failed with #{$?.exitstatus}")
end
The answer for #2 can be done several ways. You could create a controller action that simply grabbed the contents of a specific file in the filesystem, and returned the contents.
def get_file_contents
File.open(params[:file_to_read],"r") { |f| #contents = f.read }
respond_to |format|
format.js
end
end
Then create the file get_file_contents.js.erb:
$('#display_div').html('<%= escape_javascript(#contents) %>');
Then you'd have to create a timer of some kind on your page to repeatedly call that controller action, I use jquery.timers. In a timer loop you would call
$.get('/get_file_contents?file_to_read=public/logfile');
That will hit the controller, grab the file contents, and execute get_file_contents.js.erb, which would update the div with the current contents of the file.
You'd have to add the route /get_file_contents to routes.rb.