vendredi 25 juin 2021

Action Cable Signaling Server not working on different networks

I have an issue with my Ruby on rails 6 app. I make a video chat app with signaling-server js (WebRTC JS) and action-cable. video chat working fine on the same network in production. but it's not working on a different network. connection is established but video not streaming. it's not showing some error.

signaling_server.js file.

import consumer from "./channels/consumer";

// Broadcast Types
const JOIN_ROOM = "JOIN_ROOM";
const EXCHANGE = "EXCHANGE";
const REMOVE_USER = "REMOVE_USER";

// DOM Elements
let currentUser;
let localVideo;
let remoteVideoContainer;
let user;

// Objects
let pcPeers = {};
let localstream;

window.onload = () => {
  user = document.getElementById("current-user");
  if(user) {
    currentUser = document.getElementById("current-user").innerHTML;
    localVideo = document.getElementById("local-video");
    remoteVideoContainer = document.getElementById("remote-video-container");
  }
};

// Ice Credentials
const ice = { iceServers: [{ urls: "stun:stun.l.google.com:19302" }] };

// Add event listener's to buttons
document.addEventListener("DOMContentLoaded", () => {
  const joinButton = document.getElementById("join-button");
  const leaveButton = document.getElementById("leave-button");

  joinButton.onclick = handleJoinSession;
  leaveButton.onclick = handleLeaveSession;
});

// Initialize user's own video
document.onreadystatechange = () => {
  if (document.readyState === "interactive") {
    navigator.mediaDevices
      .getUserMedia({
        audio: true,
        video: true,
      })
      .then((stream) => {
        localstream = stream;
        localVideo.srcObject = stream;
        localVideo.muted = true;
      })
      .catch(logError);
  }
};

const handleJoinSession = async () => {
  consumer.subscriptions.create("VideoSessionChannel", {
    connected: () => {
      broadcastData({
        type: JOIN_ROOM,
        from: currentUser,
      });
    },
    received: (data) => {
      console.log("received", data);
      if (data.from === currentUser) return;
      switch (data.type) {
      case JOIN_ROOM:
        return joinRoom(data);
      case EXCHANGE:
        if (data.to !== currentUser) return;
        return exchange(data);
      case REMOVE_USER:
        return removeUser(data);
      default:
        return;
      }
    },
  });
};

const handleLeaveSession = () => {
  for (let user in pcPeers) {
    pcPeers[user].close();
  }
  pcPeers = {};

  consumer.unsubscribe();
  remoteVideoContainer.innerHTML = "";

  broadcastData({
    type: REMOVE_USER,
    from: currentUser,
  });
};

const joinRoom = (data) => {
  createPC(data.from, true);
};

const removeUser = (data) => {
  console.log("removing user", data.from);
  let video = document.getElementById(`remoteVideoContainer+${data.from}`);
  video && video.remove();
  delete pcPeers[data.from];
};

const createPC = (userId, isOffer) => {
  let pc = new RTCPeerConnection(ice);
  pcPeers[userId] = pc;

  console.log('createPC');
  // for (const track of localstream.getTracks()) {
  //   pc.addTrack(track, localstream);
  // }

  pc.addStream(localstream);

  isOffer &&
    pc
      .createOffer()
      .then((offer) => {
        console.log('createPC createOffer');
        return pc.setLocalDescription(offer);
      })
      .then(() => {
        broadcastData({
          type: EXCHANGE,
          from: currentUser,
          to: userId,
          sdp: JSON.stringify(pc.localDescription),
        });
      })
      .catch(logError);

  pc.onicecandidate = (event) => {
    event.candidate &&
      broadcastData({
        type: EXCHANGE,
        from: currentUser,
        to: userId,
        candidate: JSON.stringify(event.candidate),
      });
  };

  pc.onaddstream = (event) => {
    console.log(event.stream);
    const element = document.createElement("video");
    element.id = `remoteVideoContainer+${userId}`;
    element.autoplay = "autoplay";
    element.srcObject = event.stream;
    remoteVideoContainer.appendChild(element);
  };

  pc.oniceconnectionstatechange = () => {
    if (pc.iceConnectionState == "disconnected") {
      console.log("Disconnected:", userId);
      broadcastData({
        type: REMOVE_USER,
        from: userId,
      });
    }
  };

  return pc;
};

const exchange = (data) => {
  let pc;
  if (!pcPeers[data.from]) {
    pc = createPC(data.from, false);
  } else {
    pc = pcPeers[data.from];
  }

  if (data.candidate) {
    pc.addIceCandidate(new RTCIceCandidate(JSON.parse(data.candidate)))
      .then(() => console.log("Ice candidate added"))
      .catch(logError);
  }

  if (data.sdp) {
    const sdp = JSON.parse(data.sdp);
    pc.setRemoteDescription(new RTCSessionDescription(sdp))
      .then(() => {
        if (sdp.type === "offer") {
          pc.createAnswer()
            .then((answer) => {
              console.log('exchange createAnswer');
              return pc.setLocalDescription(answer);
            })
            .then(() => {
              broadcastData({
                type: EXCHANGE,
                from: currentUser,
                to: data.from,
                sdp: JSON.stringify(pc.localDescription),
              });
            });
        }
      })
      .catch(logError);
  }
};

const broadcastData = (data) => {
  /**
   * Add CSRF protection: https://stackoverflow.com/questions/8503447/rails-how-to-add-csrf-protection-to-forms-created-in-javascript
   */
  const csrfToken = document.querySelector("[name=csrf-token]").content;
  const headers = new Headers({
    "content-type": "application/json",
    "X-CSRF-TOKEN": csrfToken,
  });

  fetch("sessions", {
    method: "POST",
    body: JSON.stringify(data),
    headers,
  });
};

const logError = (error) => console.warn("Whoops! Error:", error);

routes.rb file

  mount ActionCable.server, at: "/cable"

Video Sessions Controller

class VideoSessionsController < ApplicationController
  
  def create
    head :no_content
    ActionCable.server.broadcast "video_session_channel", session_params
  end

  private

  def session_params
    params.require(:video_session).permit(:type, :from, :to, :sdp, :candidate)
  end

end

video channel file

class VideoSessionChannel < ApplicationCable::Channel
  def subscribed
    stream_from "video_session_channel"
  end
end

video chat HTML file.

<span id="current-user"><%= @random_number %></span>
                    <div class="video-chat-content">
                        <div class="" id="remote-video-container"> </div>
                        <video id="local-video" autoplay></video>
                    </div>

enter image description here

enter image description here

lundi 21 juin 2021

How to query in database with GraphQL where to pluck only selected fields not all fields?

I want to know if we can query to pluck selected columns and the request to the database to search for only those selected columns not the whole data at the endpoint. If there is any confusion in this question please let me know.

dimanche 20 juin 2021

Byebug does not pauses in controller in RSpec request spec

I have added byebug breakpoint in spec code and it pauses the code there.

require 'rails_helper'

RSpec.describe "UsedCars", :type => :request do
  describe "POST /used_cars" do
    it "creates a used car ad" do  
      byebug # <- stop here  
      count = UsedCar.count
      post used_cars_path, used_car: attributes_for(:used_car)
      expect(UsedCar.count).to eq(count + 1)
    end
  end
end

But when I add the breakpoint in the controller-action method of the request being tested. it does not stop there. I have even tried it in the top-level before_filter for application_controller.

app/controllers/used_car_controller.rb

def create
   byebug # <- does not stop here
   ....
end

Even in the application_controller.rb

# top before_filter
before_fitler :stop
...

def stop
   byebug # does not even stop here
end

I am using Rails 3 with ruby 2.2.8

samedi 19 juin 2021

rake aborted while creating admin user

I am using ubuntu 18.4, Ruby 2.7.3 , rails 4.2.11.1, Rake 10.0.0

While trying to run the rake admin:create, I am getting the below error message. Can any one help me on this.

/home/ubuntu/.rbenv/versions/2.7.3/lib/ruby/2.7.0/uri/version.rb:3: warning: already initialized constant URI::VERSION_CODE
/home/ubuntu/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/uri-0.10.1/lib/uri/version.rb:3: warning: previous definition of VERSION_CODE was here
/home/ubuntu/.rbenv/versions/2.7.3/lib/ruby/2.7.0/uri/version.rb:4: warning: already initialized constant URI::VERSION

vendredi 18 juin 2021

How to set secure flag to active_record_store cookies

I have set cookies to store them in active_record. And followed the documentation from guides.rubyonrails and suggestions from similar case but with no luck. So far I have this in my config/initializers/session_store.rb:

Application.config.session_store :active_record_store,
:expire_after => 1.weeks.to_i,
:key => '_webapp_session',
secure: Rails.env.production?

and my cookies stay insecure.

jeudi 17 juin 2021

How to stop at a specific range in ruby loops

i have this piece of code here that generates a link for all of my questions from a database, but right now I have 10 entries and this loop will iterate 10 times. Is there a way to stop the iteration at a range of 4?

<table>
  <tr>
    <th>Question</th>
    <th>Button</th>
  </tr>
 </tr>
   <% @questions.each do |q| %>
  <tr>
    <td><%= q.question %></td>
    <td><%= link_to 'Question', show_url(q.id), method: :get %></td>
    <td><%= q.id %> Button</td>
    <% end %>
  </tr>
</table>

Any suggestions will be appreciated! Thanks.

Swiper js pagination not showing up in my ruby on rails project

My code :

  1. application.js
const mySwiper = new Swiper('.swiper-container', {
spaceBetween: 16,
loop: false,
grabCursor: true,
pagination: {
              el: '.swiper-pagination',
              clickable: true,
          },
          breakpoints: {
              640: {
                  slidesPerView: 2,
              },
              1024: {
                  slidesPerView: 3,
              },
          }
      })
}

js imports js improrts

2.html

 <div class="swiper-container">
    <div class="swiper-wrapper">
      <div class="swiper-slide">Slide 1</div>
      <div class="swiper-slide">Slide 2</div>
      <div class="swiper-slide">Slide 3</div>
      <div class="swiper-slide">Slide 4</div>
    </div>
    <div class="swiper-pagination"></div>
 </div>

imported it into the application.scss

stylesheets file

stylesheets imports

dimanche 13 juin 2021

How to display a calculation in Ruby?

I am trying to display a simple calculation for how much gas one may need for a trip. I have my logic in my view for now so that I can easily display the value. Here is the form the user fills out:

    <h1>New Trip!</h1>
        <br>
        <br>
        <%= f.label :title %>
        <%= f.text_field :title %>
        <br>
        <br>
        <%= f.label :content %>
        <%= f.text_area :content %>
        <br>
        <br>
        <%= f.label :mileage %>
        <%= f.number_field :mileage, step: :any %>
        <br>
        <br>
        <%= f.label :mpg %>
        <%= f.number_field :mpg, step: :any %>

        <br>
        <br>
        <%= f.label :amount %>
        <%= f.number_field :amount, step: :any %>

        <%= f.submit %>
    <% end %>
<% end %>

I would like to have the value of this calculation displayed next to the roadtrip they created. Here is what I have in my partial view that displays the user's trips:

 <ul>
        <% roadtrips.each do |r| %>
            <li><%= link_to r.title, roadtrip_path(r) %> - <%= r.name%> </li>%
           <p><%= (r.mileage / r.mpg)*2.90 %></p>
        <% end %>
    </ul>

When I go to create the trip and click submit I do get a nil error on '/' not sure why because I thought that's how you divide in Ruby.

Any feedback/suggestions would be greatly appreciated. Thanks in advanced!

samedi 12 juin 2021

How to Get Both Coordinates In a Nested Array?

I'm working on a chess game and want to search the nested array for the King piece K(b)and then return the coordinates.

I've tried the following method which returns 4 (the x coordinate - the index in the internal array). However, I'm trying to figure out how to also return index of the outer array. Expected output is [4, 7]:

piece = "K(b)"

def coordinates_for_piece(piece)
  @board.map { |item| item.find_index(piece) }
end

Board:

def piece_setup
    @board = Array.new(8) { Array.new([" .  ", " .  ", " .  ", " .  ", " .  ", " .  ", " .  ", " .  "]) }

    @board[0] = ["R(w)", "N(w)", "B(w)", "Q(w)", "K(w)", "B(w)", "N(w)", "R(w)"]
    @board[1] = ["P(w)", "P(w)", "P(w)", "P(w)", "P(w)", "P(w)", "P(w)", "P(w)"]
   
    @board[6] = ["P(b)", "P(b)", "P(b)", "P(b)", "P(b)", "P(b)", "P(b)", "P(b)"]
    @board[7] = ["R(b)", "N(b)", "B(b)", "Q(b)", "K(b)", "B(b)", "N(b)", "R(b)"]
end

EDIT: This is a VERY clunky way of accomplishing the goal. Looking for something more streamlined.

def coordinates_for_piece(piece)
   test = @board.map { |item| item.find_index(piece) }
   => [nil, nil, nil, nil, nil, nil, nil, 4]
   x = test.find{|x| !x.nil?}
   => 4
   y = test.find_index{|y| !y.nil?}
   => 7
   [x, y]
end

jeudi 10 juin 2021

Create a image with MiniMagick::Image getting improper image header

I'm creating a png image with MiniMagick::Image and it giving me an false result when I checked with valid? function: there are 2 error composite: ImproperImageHeader and composite: MissingAnImageFilename

Here is my code:

img = MiniMagick::Image.new(Tempfile.new(['label_creation_date', '.png']).path)

MiniMagick::Image.new(Tempfile.new(['label_creation_date', '.png']).path).tap do |tmp_image|
  MiniMagick::Tool::Convert.new.tap do |convert|
    convert << tmp_image.path
    convert.background 'transparent'
    convert.rotate '-4'
    convert << tmp_image.path.to_s
  end
end

I tried one more solution that in gives in https://github.com/minimagick/minimagick/issues/59#issuecomment-3775000 here, but unfortunately it's also not working.

Please help me how can I create a valid image from scratch with the help of minimagick?

Thanks

mardi 8 juin 2021

rails_admin gem auto sorting when stored as an array

I am using rails_admin gem

I am saving data in the form of array . The data is being stored.

I am facing an issue while editing the data. While editing and saving the data the array is auto sorting. I haven't written any sort array function.

How can I stop the auto sortarray while saving

Thank you

dimanche 6 juin 2021

Error: port 22: Resource temporarily unavailable in wsl

I am using capistrano gem to deploy my rails app on ec2 instance and i am facing Error: port 22: Resource temporarily unavailable in wsl.

I have tried the following things but facing the same problem still:

  1. eval ssh-agent -s
  2. Added inbound and outbound rule

I am not able to figure out the problem now

samedi 5 juin 2021

Improving a query. One book for each author

I need an hand to improve this query

def interesting_books
  Book.joins(:genre)
    .where(author: interesting_authors.sample(5))
    .where('ratings >= 4')
    .random_order
    .where.not(id: black_books)
    .limit(3)
end

def interesting_authors
 @interesting_authors ||= (authors_commented_books + authors_watched_books).uniq
end

def authors_commented_books
 @authors_commented_books ||= current_user.commented_books.pluck(:author).uniq
end

def authors_watched_books
 @authors_watched_books ||= current_user.watched_books.pluck(:author).uniq
end

now, in this way if in the .where(author: interesting_authors.sample(5)) i have authors like "Shakespear", "Twain" , "Fitzgerald", "Wilde" and "Darwin"... it shows only 3 books (.limit(3)) made by "Shakespear". Result: "Macbeth", "Othello" and "The Tempest".

BUT I want to show 3 books made by different (selected) authors. Like "Othello", "The Great Gatsby" and "Dorian Gray".

How to do?

vendredi 4 juin 2021

bundle install is failed on windows for ruby

Please Im trying to run bundle install but its not finished and I got that error: city.cc:91:10: fatal error: byteswap.h: No such file or directory, it said Make sure that `gem install cityhash -v '0.9.0', i did that but i got the same error saying it can't install cityhash. enter image description here

How to extract from an array of hash

people = [
    {id: 101, first_name: 'John', last_name: 'Doe'},
    {id: 102, first_name: 'Tom', last_name: 'Rogers'},
    {id: 103, first_name: 'Bill', last_name: ''}
]

I want to put a list of name like this, "John Doe, Tom Rogers, Bill"

How can i achieve this is in ruby?