Uservoice Widget for Rails 3 App - javascript

I'm having trouble displaying the Uservoice widget on my page. I copied the javascript code from the Uservoice admin, converted it to HAML then pasted on to my app:
layouts/_uservoice.html.haml
:javascript
(function(){
var uv=document.createElement('script');
uv.type='text/javascript';uv.async=true;
uv.src='//widget.uservoice.com/Qho4ZF2W4O43bJ8Opc65g.js';
var s=document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(uv,s)
})()
:javascript
UserVoice = window.UserVoice || [];
UserVoice.push(['showTab', 'classic_widget', {
mode: 'full',
primary_color: '#cc6d00',
link_color: '#007dbf',
default_mode: 'support',
forum_id: 216289,
tab_label: 'Feedback & Support',
tab_color: '#cc6d00',
tab_position: 'middle-right',
tab_inverted: false
}]);
and my home view:
<doctype html>
%html
%head
= render 'shared/meta'
= favicon_link_tag 'tgnd_favicon.png'
%body
= render 'shared/fb'
#main{:role => "main"}
= render 'shared/header'
= render 'shared/sub_header'
.content_wrap.container
.content.box_normal
= render 'layouts/messages'
= yield
/ ! end of .container
.push
= render 'layouts/uservoice'
= render 'shared/footer'
= render 'shared/dialogs'

Related

Setting state when page loads, Depending on (database?) contents

So in my code, I want it where a single User can only have one booking/reservation per Hotel, but every time after the page is refreshed, my state keeps reverting back to it's default value, even if the Hotel has already been reserved...
BTW, all of the code is functioning, it is just the state that is giving me a problem...
I've been troubleshooting and debugging the code for a couple of hours but nothing concrete so far.
I've included code from most of the files, but I can't bring in the code from all of the ones needed, or it wouldn't quite be an "minimal" reproducible example, so I'll try to summarize the structure here:
There is a many-to-many relationship between Users and Hotels, which has Bookings belonging to both. This enables me to use hotel.users, etc.
I've just tried adding in a new state (const [bookingObject, setBookingObject] = useState();), but I haven't been able to get it to give me a truthy value 100% of the time... Can anyone see what it is that I'm doing wrong? Anyone have any suggestions or ideas?
bookings_controller.rb:
class BookingsController < ApplicationController
skip_before_action :authorize, only: [:create, :destroy]
def show
render json: #booking
end
def create
booking = Booking.new(booking_params)
if booking.save
render json: booking, status: :created
else
render json: {errors: "Something went wrong!"}
end
end
def destroy
#booking = Booking.find(params[:id])
#booking.destroy
end
private
def set_booking
#booking = Booking.find(params[:id])
end
def booking_params
params.require(:booking).permit(:id, :user_id, :hotel_id)
end
end
hotels_controller.rb:
class HotelsController < ApplicationController
skip_before_action :authorize, only: [:create, :destroy]
def index
render json: Hotel.all
end
def show
render json: #hotel
end
def hotel_params
params.require(:hotel).permit(:name, :city, :country, :company)
end
end
Hotel.jsx:
import React, {useContext, useState} from 'react';
const {bookings, setBookings} = useContext(BookingsContext);
const [booked, setBooked] = useState(false);
const [bookingObject, setBookingObject] = useState();
function toggleBooking(e){
if(booked){
const booking = bookings.find(booking => {return booking.hotel.id == e.target.id});
deleteBookings(booking.id);
setBooked(!booked);
} else if(booked === false){
postBookings();
setBooked(!booked);
}
}
function postBookings(){
const newBooking={
user_id: (currentUser.id),
hotel_id: (hotel.id)
}
fetch(`http://localhost:3001/users/${currentUser.id}/bookings`, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
booking: newBooking
}),
}).then((r) => r.json())
.then((data) => {
setBookingObject(data);
setBookings([...bookings, data]);
})
}
function deleteBookings(bookingId){ fetch(`http://localhost:3001/users/${currentUser.id}/bookings/${bookingId}`, {
method: "DELETE"
})
.then((r) => {
if(r.ok)onDeleteBookings(bookingId);
})
}
function onDeleteBookings(deletedBooking){
const updatedBookings = bookings.filter((booking) => booking.id !== deletedBooking.id);
setBookings(updatedBookings);
setBookingObject();
}
return(
<div id='hotels'>
<p>{hotel.name}</p><p>{hotel.city}, {hotel.country}</p>
<button id={hotel.id} onClick={toggleBooking} >{booked ? ("Booked") : ("Book Now")}</button>
</div>
);
}
export default Hotel;

ActionCable not getting data on Rails

I am trying to build a chat feature in my app and initially, the action cable had worked for it seems like it is not getting any data to broadcast. I have tried to console log in the chatroom_channel.js but the "data" is not being populated on the console.
initChatroomChannel is also exported from application.js
I have also tried to use the solution from the ticket below but that also did not help out.
ActionCable Not Receiving Data
There's are the related files.
Thank you
Onur
messages_controller
class MessagesController < ApplicationController
def create
#chatroom = Chatroom.find(params[:chatroom_id])
#message = Message.new(message_params)
#message.chatroom = #chatroom
#message.user = current_user
if #message.save
ChatroomChannel.broadcast_to(
#chatroom,
render_to_string(partial: "message", locals: { message: #message })
)
redirect_to chatroom_path(#chatroom, anchor: "message-#{#message.id}")
else
render "chatrooms/show"
end
end
def message_params
params.require(:message).permit(:content)
end
chatrooms_controller
class ChatroomsController < ApplicationController
def index
#chatrooms = []
all_chatrooms = Chatroom.all
all_chatrooms.each do |chatroom|
#chatrooms << chatroom if (current_user.id == chatroom.engager_id || current_user.id == chatroom.receiver_id)
end
end
def show
chat = Chatroom.find(params[:id])
if (current_user.id == chat.engager_id || current_user.id == chat.receiver_id)
#message = Message.new
#chatroom = chat
else
redirect_to chatrooms_path
end
end
def destroy
#chatroom = Chatroom.find(params[:id])
#chatroom.destroy
redirect_to chatrooms_path
end
end
chatroom_channel.rb
class ChatroomChannel < ApplicationCable::Channel
def subscribed
# stream_from "some_channel"
chatroom = Chatroom.find(params[:id])
stream_for chatroom
end
# def unsubscribed
# # Any cleanup needed when channel is unsubscribed
# end
end
chatroom_channel.js
import consumer from "./consumer";
const initChatroomCable = () => {
const messagesContainer = document.getElementById('messages');
if (messagesContainer) {
const id = messagesContainer.dataset.chatroomId;
consumer.subscriptions.create({ channel: "ChatroomChannel", id: id }, {
received(data) {
console.log(data)
messagesContainer.insertAdjacentHTML("beforeend", data)
},
});
}
}
export { initChatroomCable };
application.js
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
Rails.start()
Turbolinks.start()
ActiveStorage.start()
// External imports
import "bootstrap";
import { loadDynamicBannerText } from '../componets/banner';
// Internal imports, e.g:
import { initChatroomCable } from '../channels/chatroom_channel';
document.addEventListener('turbolinks:load', () => {
initChatroomCable();
jQuery.fn.carousel.Constructor.TRANSITION_DURATION = 2000
var $item = $('.carousel-item');
var $wHeight = $(window).height();
$item.eq(0).addClass('active');
$item.height($wHeight * 0.75);
$item.addClass('full-screen');
$('.carousel img').each(function () {
var $src = $(this).attr('src');
var $color = $(this).attr('data-color');
$(this).parent().css({
'background-image': 'url(' + $src + ')',
'background-color': $color
});
$(this).remove();
});
$(window).on('resize', function () {
$wHeight = $(window).height();
$item.height($wHeight * 0.75);
});
$('.carousel').carousel({
interval: 6000,
pause: "false"
});
const banner = document.getElementById("banner-typed-text")
if (banner) {
loadDynamicBannerText();
}
});
import "controllers"
_message.html.erb
<div class="message-container" id="message-<%= message.id %>">
<i class="author">
<% User.find(message.user_id).name ? name = User.find(message.user_id).name : name = "Unknown Cat" %>
<span><%= User.find(message.user_id) == current_user ? "me" : name %></span>
<small><%= message.created_at.strftime("%a %b %e at %l:%M%p") %></small>
</i>
<p><%= message.content %></p>
</div>
cable.yml
development:
adapter: async
test:
adapter: test
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: Cat_Tinder_production

rails vue.js deep nested (attributes of attribute)

I created one nested form by watching gorails tutorial It is fine and i done it. Issue started when i want to creat nested model under on other nested model. I have Survey model and it is main model. Then i added Question model and made form with vue.js. So I added Choice model under question ( you can notice in survey controller params) First problem is; i don't know how i can define/implemen in vue.js control.(hello_vue.js) And second importan point is: how i can create form elements in new.html
This is my survey.rb model:
class Survey < ApplicationRecord
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, allow_destroy: true
belongs_to :user
end
and surveys_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
def survey_params
params.require(:survey).permit(:user_id, :name, questions_attributes:[:id,:survey_id, :title, :qtype, :_destroy, choices_attributes:[:id,:question, :ctext]])
end
end
This is nested model of Survey : question.rb:
class Question < ApplicationRecord
enum qtype: [:multiple_choice, :check_boxes, :short_answer]
belongs_to :survey
has_many :choices
accepts_nested_attributes_for :choices, allow_destroy: true
end
So finaly vue.js file:
import TurbolinksAdapter from 'vue-turbolinks'
import Vue from 'vue/dist/vue.esm'
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.use(TurbolinksAdapter)
Vue.component('app', App)
document.addEventListener('turbolinks:load', () => {
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
var element = document.getElementById("survey-form")
if (element != null){
var survey = JSON.parse(element.dataset.survey)
var questions_attributes = JSON.parse(element.dataset.questionsAttributes)
var choices_attributes = JSON.parse(element.dataset.choicesAttributes)
questions_attributes.forEach(function(question) { question._destroy = null })
survey.questions_attributes = questions_attributes
var app = new Vue({
el: element,
//mixins: [TurbolinksAdapter],
data: function(){
return { survey: survey }
},
methods:{
addQuestion: function(){
this.survey.questions_attributes.push({
id: null,
title:"",
qtype:"",
_destroy: null
})
},
removeQuestion: function(index) {
var question = this.survey.questions_attributes[index]
if (question.id == null) {
this.survey.questions_attributes.splice(index, 1)
} else {
this.survey.questions_attributes[index]._destroy = "1"
}
},
undoRemove: function(index) {
this.survey.questions_attributes[index]._destroy = null
},
saveSurvey: function() {
// Create a new survey
if (this.survey.id == null) {
this.$http.post('/surveys', { survey: this.survey }).then(response => {
Turbolinks.visit(`/surveys/${response.body.id}`)
}, response => {
console.log(response)
})
// Edit an existing survey
} else {
this.$http.put(`/surveys/${this.survey.id}`, { survey: this.survey }).then(response => {
Turbolinks.visit(`/surveys/${response.body.id}`)
}, response => {
console.log(response)
})
}
},
existingSurvey: function() {
return this.survey.id != null
}
}
})
}
})
_form.html.erb
<%= content_tag :div,
id: "survey-form",
data: {
survey: survey.to_json(except: [:created_at, :updated_at]),
questions_attributes: survey.questions.to_json,
} do %>
<label>Survey Name</label>
<input qtype="text" v-model="survey.name">
<h4>Questions</h4>
<div v-for="(question, index) in survey.questions_attributes">
<div v-if="question._destroy == '1'">
{{ question.title }} will be removed. <button v-on:click="undoRemove(index)">Undo</button>
</div>
<div v-else>
<label>Question</label>
<input qtype="text" v-model="question.title" />
<label>Qestion qtype</label>
<select v-model="question.qtype">
<option v-for="qtype in <%= Question.qtypes.keys.to_json %>"
:value=qtype>
{{ qtype }}
</option>
</select>
<button v-on:click="removeQuestion(index)">Remove</button>
</div>
<hr />
</div>
<button v-on:click="addQuestion">Add Question</button>
<br>
<button v-on:click="saveSurvey" >Save Survey</button>
<% end %>
I followed this same tutorial and started running into issues using JSON.parse with more complex nested attributes. Try using Jbuilder to build your JSON objects and look into the gon gem to pass your Rails variables into Javascript. It'll be much easier to query your database and pass the results into your Javascript file using the nested naming that Rails needs. For example...
survey = #survey
json.id survey.id
json.survey do
json.(survey, :user_id, :name)
json.questions_attributes survey.questions do |question|
json.(question, :id, :title, :qtype, :_destroy)
json.choices_attributes question.choices do |choice|
json.(choice, :id, :ctext)
end
end
end
It allows you to do things like...
var survey = gon.survey
Instead of...
var survey = JSON.parse(element.dataset.survey)
And you can pass gon.jbuilder from your controller action and have your defined JSON object ready and available in Vue.

Move chart.js function from partial to assets folder in .coffee file

I have text block in main page, it located in _about.html.haml partial. When I click the link, text replaces by radar chart via AJAX (I use 'chart-js-rails' gem). Now the js function located in _my-chart.html.haml partial (which replaces first one) & I think it's not good enough.
So the question is: how to move this function code to assets folder in .coffee file or something like that?
P.S. I already try to move it to 'chart.js' file & use = javascript_include_tag 'chart.js' but it's not working graph doesn't render & I have empty canvas element.
views/welcome/_about.html.haml
%div{id: 'about'}
%h2 About
%p Some text
= link_to 'View chart', welcome_chart_path, remote: true
views/welcome/chart.js.haml
$('#about').replaceWith('#{j render(partial: 'welcome/my-chart')}');
views/welcome/_my-chart.html.haml
%div
%h2 Chart
%canvas{id: 'my-chart', width: '400', height: '400'}
:javascript
$(function() {
var ctx = $('#my-chart');
var data = {
labels: [a, b, c],
datasets: [
{data: [1, 2, 3]}
]
};
var my_chart = new Chart(ctx, {
type: 'radar',
data: data
})
});
controllers/welcome_controller.rb
class WelcomeController < ApplicationController
respond_to :js, only: [:chart]
...
def chart; end
end

Customer is not getting created in braintree (js+python)

I am getting error while creating customer
AuthenticationError at /vissa/assign-plan/
My js
<script src="https://js.braintreegateway.com/v2/braintree.js"></script>
{% if cust %}
$(document).ready(function() {
braintree.setup("{{ client_token }}", "dropin", {
container: "checkout",
form: "checkoutForm"
});
$("#submitPayment").on("click", function () {
$("button").off("click");
$("a").off("click");
$('body').off("click");
var btn = $(this).button("loading")
setTimeout(function () {
btn.button('reset');
}, 3500)
});
});
</script>
{% endif %}
And client token i am trying to get in context processor.
def payment_data(request):
try:
userone = UserProfile.objects.get(user=request.user)
indi_user = IndividualUser.objects.get(user_profile=userone)
plan = int(indi_user.selected_plan)
amount = int(plan)
except:
plan = None
amount = None
try:
merchant_obj = UserMerchantId.objects.get(user=request.user)
cust = True
merchant_customer_id = merchant_obj.customer_id
print merchant_customer_id
client_token = braintree.ClientToken.generate({
"customer_id": merchant_customer_id
})
except:
cust = False
client_token = None
try:
custom = Transaction.objects.filter(user=request.user)[0]
paid = custom.success
except:
paid = False
return {'cust':cust, "plan":plan,"amount": amount, "paid": paid,"client_token":client_token} #"plan": plan}
but i am getting above error.
if i tried
client_token = braintree.ClientToken.generate()
getting authentication error.
I am not getting how to create client token in django.
is there a way to create client token without customer_id?
Creating customer.
def new_user_receiver( instance, *args, **kwargs):
try:
merchant_obj = UserMerchantId.objects.get(user=instance)
except:
new_customer_result = braintree.Customer.create({
"first_name": instance.first_name,
"last_name": instance.last_name,
"email": instance.email,
"phone": instance.get_profile().telephone_number
})
if new_customer_result.is_success:
merchant_obj, created = UserMerchantId.objects.get_or_create(user=instance)
merchant_obj.customer_id = new_customer_result.customer.id
merchant_obj.save()
print """Customer created with id = {0}""".format(new_customer_result.customer.id)
else:
print "Error: {0}".format(new_customer_result.message)
It worked after making the change
import braintree
braintree.Configuration.configure(braintree.Environment.Production,
merchant_id=settings.BRAINTREE_MERCHANT_ID,
public_key=settings.BRAINTREE_PUBLIC_KEY,
private_key=settings.BRAINTREE_PRIVATE_KEY)
in production instead of "Sandbox" need to use "Production".

Categories

Resources