Rails 6, ActionCable display data contains HTML tags - ruby-on-rails-6

I'm trying to use a partial via ActionCable as follows:
#app/channels/comments_channel.rb
class CommentsChannel < ApplicationCable::Channel
def self.broadcast(comment)
broadcast_to comment.post, comment:
CommentsController.render(partial: 'comments/comment', locals: { comment: comment})
end
def subscribed
stream_for Post.last
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
here is the JS part:
#app/javascript/comments_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("CommentsChannel", {
connected() {
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
const commentsId = document.getElementById('comments');
commentsId.append(data.comment);
}
});
callin it in the CommentsController:
#app/controllers/comments_controller.rb
...
def create
comment = #post.comments.create! comments_params
CommentsMailer.submitted(comment).deliver_later
CommentsChannel.broadcast(comment)
redirect_to #post
end
and finally, the comments/_comment partial:
#app/views/comments/_comment.html.erb
<p><%= comment.body%>--<%= comment.created_at.to_s(:long)%></p>
It works but displays HTML tags when posting a new comment. If I reload the page, no HTML tags displayed:
What am I missing?

The solution that worked for me was to use insertAdjacentHTML as follows in the comments_channel.js:
#app/javascripts/channels/comments_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("CommentsChannel", {
...
received(data) {
const commentsId = document.getElementById('comments');
commentsId.insertAdjacentHTML('beforeend', data.comment);
}
Hope this helps.

Related

Meteor query runs perfectly fine on server but not on client

So I have a simple server file:
import { Meteor } from 'meteor/meteor';
const Animals = new Mongo.Collection("animals");
let animalsFindOne = Targets.findOne({animal: "henry"});
console.log(_.get(animalsFindOne, 'food.favorite.amount'));
And a animals.js file that renders to the template
import {Template} from "meteor/templating";
import {Mongo} from "meteor/mongo";
import "/imports/ui/targets/animals.html";
const Animals = new Mongo.Collection("animals");
let animalsFindOne = Targets.findOne({animal: "henry"});
Template.targets.helpers({
foodAmount: function() {
return _.get(animalsFindOne, 'food.favorite.amount';
}
});
I could return "foo" as foodAmount and the template would render it perfectly fine. For _.get I use erasaur:meteor-lodash, which works perfectly fine in server.js. In the server console the output is "5", the output that is expected and great.
What piece am I missing here?
Edit: Also I have autopublish installed, and I am not looking forward to removing it, as this software is a test anyways.
The animalsFindOne is already defined outside the foodAmount helper, thus it won't trigger the Template's reactivity-based redrawing mechanism.
In order to gain reactivity in helpers you need to call queries within the helper:
import {Template} from "meteor/templating";
import {Mongo} from "meteor/mongo";
import "/imports/ui/targets/animals.html";
const Animals = new Mongo.Collection("animals");
Template.targets.helpers({
foodAmount: function() {
let animalsFindOne = Targets.findOne({animal: "henry"});
return _.get(animalsFindOne, 'food.favorite.amount';
}
});
edit: Meteor allows optional chaining with the more recent versions, so no need for lodash here:
Template.targets.helpers({
foodAmount: function() {
let animalsFindOne = Targets.findOne({animal: "henry"});
return animalsFindOne?.food?.favorite?.amount
}
});

Collection.insert is not a function - Meteor

Good day developers! I'm working with Meteor.js it's my 1st expirience
I created collection in file
// ./dbs/messages.js
import { Mongo } from 'meteor/mongo';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
export const Messages = new Mongo.Collection('messages');
and use it in api point with calling Messages.insert like that
// server/mail.js
import Messages from './dbs/messages.js';
Meteor.methods({
'message.post'(messageText, location){
Messages.insert({
messageText: messageText,
location: location
});
}
})
But when I call 'message.post' I get an error
Exception while invoking method 'message.post' TypeError
Messages.insert is not a function
BUT, when I comment collection import and declare it in server/main.js like that
// import Messages from './dbs/messages.js';
const Messages = new Mongo.Collection('messages');
Meteor.methods({
'message.post'(messageText, location){
Messages.insert({
messageText: messageText,
location: location
});
}
});
In this case my Messages.insert works properly.
Who has experience with Meteor - can you explain me what is the reason?
Thanks!
Also I have removed autopublish and insecure packages
As #MasterAM and #Ankur Soni said you need to import Messages using brackets import { Messages } from './dbs/messages.js';
The only way to import without brackets is by defining Messages and then exporting it like so export default Messages;
I initiate my collections in a "common" space. I feel what you did is actually right. You either declare the collection twice, once on the client side and once on the server side or do it only once in a common folder. I see in many documentations that the popular place to keep these declarations is the /imports/api ... which is common to both server and client.
Rgs,
Paul

angular 2 - asynchrone issue

I have a very simple Typescript script (ionic2 and angular2) that add an authentication header before an HTTP call. Here is the idea (simplified code):
function CreateAuthorization(){
this.header.append('tests' : 'test')
Storage.retrieve('Auth').then(data){
this.header.append('authorization' : data.token)
}
}
function customHttp(url){
CreateAuthorization();
Http.get(url, this.header);
}
In my Request header, I have 'test' = 'test' but I do NOT have 'authorization' = 'MyToken'.
How can I make in sort to "wait" for the header to be set in Storage.retrieve('Auth') ?
I know that I can use a setTimeout() but I don't like this dirty workaround.
The solution could be an observable/promise but I don't really master those things.
Any help would be very appreciated :)
Geoffrey
It's because your CreateAuthorization method is asynchronous. I would try something like that leveraging promise chaining to be notified when the Authorization header is actually added:
createAuthorization() {
this.header.append('tests' : 'test');
return Storage.retrieve('Auth').then(data){
this.header.append('authorization', data.token);
return true;
}
}
customHttp(url) {
this.createAuthorization().then(() => {
this.http.get(url, { headers: this.header });
});
}

cannot load Java class uk.co.jaywayco.Parser

I am trying to write a custom logstash filter. I have followed the documentation here.
My filter (at the minute) looks like:
# Call this file 'foo.rb' (in logstash/filters, as above)
require "logstash/filters/base"
require "logstash/namespace"
class LogStash::Filters::NLP < LogStash::Filters::Base
# Setting the config_name here is required. This is how you
# configure this filter from your logstash config.
#
# filter {
# foo { ... }
# }
config_name "nlp"
# New plugins should start life at milestone 1.
milestone 1
# Replace the message with this value.
config :message, :validate => :string
public
def register
# nothing to do
java_import 'uk.co.jaywayco.Parser'
end # def register
public
def filter(event)
# return nothing unless there's an actual filter event
return unless filter?(event)
if #message
# Replace the event message with our message as configured in the
# config file.
event["message"] = #message
end
# filter_matched should go in the last line of our successful code
filter_matched(event)
end # def filter
end # class LogStash::Filters::NLP
Ive created a very simple logstash config that looks like this:
input {
stdin { type => "nlp" }
}
filter {
if [type] == "nlp" {
nlp {
message => "Hello world! - Youve been NLP'd"
}
}
}
output {
stdout { }
}
When i run logstash with the following command:
bin/logstash -f /etc/logstash/conf.d/test.conf
I get the following error:
The error reported is:
enter code herecannot load Java class uk.co.jaywayco.Parser
The java class uk.co.jaywayco.Parser is in a jar file located in the /opt/logstash/lib/logstash/filters folder. Which is where all the filter scripts reside.
Why wont logstash load my java class?
Ok so thanks to the logstash IRC channel
The solution was to add require 'logstash/filters/myjarfile.jar' wher the other requires are

Meteor/Iron-Router: how to define routes using data from settings.json

For the URL to which a route applies I have a part defined in settings.json, like this
baseUrl: '/private'
My settings are published and accessible through the collections 'Settings' (on the client). So I tried the following:
Meteor.subscribe('settings');
Deps.autorun(function () {
var settings = Settings.findOne():
if (settings) {
Router.map(function () {
this.route('project', {
path: settings.baseUrl + '/:projectId,
controller: 'ProjectController'
});
});
}
});
The problem is that during initialisation the data is not yet on the client available, so I have to wait until the data is present. So far this approach doesn't work (yet). But before spending many hours I was wondering if someone has done this before or can tell me if this is the right approach ?
Updated answer:
I published solution in repository : https://github.com/parhelium/meteor-so-inject-data-to-html
. Test it by opening url : localhost:3000/test
In this case FastRender package is useless as it injects collection data in the end of head tag -> line 63.
Inject-Initial package injects data in the beginning of head tag -> line 106.
Needed packages:
mrt add iron-router
mrt add inject-initial
Source code:
Settings = new Meteor.Collection("settings");
if (Meteor.isClient) {
var settings = Injected.obj('settings');
console.log(settings);
Router.map(function () {
this.route('postShow', {
path: '/'+settings.path,
action: function () {
console.log("dynamic route !");
}
});
});
}
if (Meteor.isServer){
if(Settings.find().count() == 0){
Settings.insert({path:"test",data:"null"});
}
Inject.obj('settings', Settings.findOne());
}
Read about security in the bottom of the page : https://github.com/gadicc/meteor-inject-initial/
OLD ANSWER :
Below solution won't work in this specific case as FastRender injects data in the end of head tag. Because of that Routes are being initialized before injected data is present.
It will work when data from Settings collection will be sent together with html.
You can do that using package FastRender.
Create file server/router.js :
FastRender.onAllRoutes(function(path) {
// don't subscribe if client is downloading resources
if(/(css|js|html|map)/.test(path)) {
return;
}
this.subscribe('settings');
});
Create also publish function:
Meteor.publish('settings', function () {
return Settings.find({});
});
The above code means that if user open any url of your app then client will subscribe to "settings" publication and data will be injected on the server into html and available for client immediately.
I use this approach to be able to connect many different domains to meteor app and accordingly sent proper data.

Resources