How to dynamically update other pages' content - javascript

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.

Related

How to use permission based functions in react frontend with Django Rest API?

I use Django Rest Framework with React on the frontend. I use Token Athentication and everything works fine. I now want to implement some permission based functions in my React frontend. More specifically, I want the author of a post to be able to edit the post, but all other users not. How can I achieve this?
My idea is that I add an is_viewing_own_story as a boolean to the user model in the django backend. When the author now clicks on the post, redux updates this state to 'true' and the buttons for deleting and updating stories appear (if is_viewing_own_story=true show buttons else show nothing).
I'm not sure if this is the smartest way or if there is a best practice?
If there is anything to read about, or any git hub repo to inform im happy to study that.
server should send user id for frontend and front check that id with current user
and
backend should set permissions for that api
like this :
class PostOwnerPermssion(BasePermission):
def has_object_permission(self,request,obj,**kwargs):
if request.user.id = obj.user.id:
return True
return False

User details being displayed in the browser dev tools

I have a rails application where i am using javascript. Now when the user logsin inside the application i can see all the user details(email,pw,phone etc.) in the Network->Preview section of the browser dev tools. Is there a way to hide it in rails? so that when i open the browser dev tools i dont see the user details. I am using React js in the front end.
As far as I could understand, this is an authorization issue. You probably want to have different roles for your users and, based on such roles, decide what to display.
You may use policies to define which content each user is allowed to access. To this end, you could use the pundit gem. It is very useful to define authorization mechanisms for controller actions.
If different users can access the same route but you need to hide some fields/details for some of them, you should pass the current_user to your serializations. For example, if you are using the Active Model Serializers gem, you need to add the current_user to the scope of your serializers:
class ApplicationController < ActionController::Base
serialization_scope :current_user
end
And then use that scope to display user details:
class UserSerializer < BaseSerializer
attribute :name # Everyone can see
attribute :email do # Only admins can see
user = scope
if user
if user.admin?
object.email
end
end
end
end
This article have a deeper discussion regarding authorization in rails apps

Utilizing Javascript 'onbeforeload' on rails

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.

rspec testing: putting :js => true also affects the before block

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.

Tailing Logfile in Ruby On Rails 3.1

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.

Categories