# #ruby-on-rails #firebase #react-native #devise #firebase-cloud-messaging
Вопрос:
У меня есть следующая настройка:
Сервер rails, который имеет базовый логин пользователя с использованием драгоценного камня devise. Там я определил User
и Device
модель, в которой у каждого пользователя может быть несколько устройств через has_many
связь с пользователем. Device
Модель имеет один атрибут — токен, который я бы использовал для отправки push-уведомлений с помощью драгоценного камня rpush.
Приложение react-native, использующее пакет react-native-webview и пакет react-native-firebase/обмена сообщениями. Дело в том, что я действительно не знаю, как правильно отправить маркер устройства firebase на сервер.
Что у меня есть до сих пор, так это то, что я переопределил registrations#new
представление о разработке рельсов следующим образом:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<%= f.fields_for :devices, @user do |f| %>
<div class="field">
<%= f.hidden_field :token, {value: nil} %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Здесь вы можете видеть, что я добавил скрытое поле для токена, которое я вставляю в приложение react-native, как только я попал на /users/sign_up
страницу, используя следующий код:
import React, { useState } from "react";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyWebView = () => {
const [uri] = useState("http://10.0.2.2:3000");
const [webViewRef, setWebViewRef] = useState(null);
const postMessageThatTurbolinksLoadOccured = `
document.addEventListener("turbolinks:load", () => {
window.ReactNativeWebView.postMessage("turbolinks:load");
})`;
function onMessage(obj) {
const event = obj.nativeEvent;
if(event.data != "turbolinks:load") return;
if(event.url==`${uri}/users/sign_in` || event.url==`${uri}/users/sign_up`) {
messaging().getToken().then(token => {
const insertTokenCode = `
document.getElementById("user_devices_attributes_0_token").value = "${token}";
`;
webViewRef.injectJavaScript(insertTokenCode);
})
}
}
// This is here only temporarily
messaging().onMessage(remoteMessage => {
Alert.alert(remoteMessage.notification.body);
})
return (
<WebView
ref={setWebViewRef}
source={{ uri: `${uri}/users/sign_in` }}
injectedJavaScript={postMessageThatTurbolinksLoadOccured}
onMessage={onMessage}
/>
);
};
export default MyWebView;
И это на самом деле работает нормально, но как только я приступил к тестированию приложения rails и попытался установить значение скрытого поля в спецификациях, я получил ошибку:
Selenium::WebDriver::Error::ElementNotInteractableError:
element not interactable
Что заставило меня подумать, что этот подход «халтурный». Итак, кто-нибудь знает лучший подход?
Ответ №1:
Для всех,кто также сталкивается с этой проблемой, я понял это некоторое время назад, но не удосужился ответить на этот вопрос.
Я начал использовать каналы firebase вместо того, чтобы регистрировать каждое устройство на сервере и вместо этого просто отправлять сообщение на канал, что избавляет меня от необходимости сохранять идентификатор каждого устройства на сервере. Вот так:
- Для приложения react-native
import { Alert } from "react-native";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyView = () => {
const messagingInstance = messaging()
messagingInstance.subscribeToTopic("welcome").then(() => {
messagingInstance.onMessage(message => {
if(message.from == "/topics/welcome") {
Alert.alert(message.notification.body);
messagingInstance.unsubscribeFromTopic("welcome");
}
});
});
return (
<WebView
source={{ uri: `http://10.0.2.2:3000` }}
/>
);
};
export default MyView;
- на сервере у меня есть задание, которое отправляет уведомление по каналу с помощью fcm gem
class SendGreetingPushNotificationJob < ApplicationJob
queue_as :default
def perform(*args)
fcm = FCM.new(Rails.application.config.FIREBASE_SERVER_KEY)
fcm.send_to_topic("welcome", notification: {body: "Welcome to MyApp!"})
end
end