I have been trying to convert the views of a project written initially in Ruby on Rails and I have pretty much succeeded in it. The next step is to write React APIs that will request and send data to the rails models. Here is where I am stuck.
So Initially I had to write the APIs for user registration, login and logout which I have succeeded in but now I need to write APIs for the nested resources and I am not able to solve the issue.
So the scenario in the application is that each user can have many projects and each project will have one project manager (from user model) and can have multiple developers and QAs (also from user table). The project manager of each project is being managed through a foreign key named "manager_id" in the projects table while the developers and QAs of the projects are being managed through a has_and_belongs_to_many association and hence through a join table as well.
My model of user and project is following
Project.rb:
class Project < ApplicationRecord
belongs_to :project_manager, class_name: 'User', foreign_key: :manager_id
has_and_belongs_to_many :users
end
User.rb:
class User < ApplicationRecord
has_many :projects_as_project_manager, class_name: 'Project', foreign_key: :manager_id
has_and_belongs_to_many :projects
end
After running through the rake routes command I get to see that the URI for projects#create is /users/:user_id/projects(.:format)
For project creation, I have created a form and on submit I am sending the post request in the following way
const saveProject = (e) => {
const API_URL = "http://localhost:3000/users/" + user_details.id + "/projects";
e.preventDefault();
const temp_project = {title: title, deadline: deadline, status: status, manager_id: user_details.id};
axios.post(API_URL, temp_project).then((promise) => {
console.log("Response in promise is: ", promise);
}).catch((error) => {
console.log("error in catch block is: ", error);
})
}
For clarification purposes let me state that project users(developers and qas) can be null as well so I am just sending manager id in addition to the project form field.
But I am getting the following error. Kindly help me out here
The code above is a javascript code. You should render Ruby variables in erb in order to view the ruby variables. for instance <%= user_details.id %> Check the code beneath.
If the source of the javascript code is in a js.erb file then you should make the variables ~> instance variables. i.e #user_details so that you can access them in the js file like this: <%= #user_details.id %>.
const saveProject = (e) => {
const API_URL = "http://localhost:3000/users/" + <%= user_details.id %> + "/projects";
e.preventDefault();
const temp_project = {title: <%= title %>, deadline: <%= deadline %>, status: <%= status %>, manager_id: <%= user_details.id %>};
axios.post(API_URL, temp_project).then((promise) => {
console.log("Response in promise is: ", promise);
}).catch((error) => {
console.log("error in catch block is: ", error);
})
}
Finally I was able to find out the mistake which infact was a really stupid one. I had not generated the controller for projects model and that's why I was getting the bad request error as the request being generated from axios was not being submitted anywhere.
Related
Just started using the Realm MongoDB and i watched this video https://www.youtube.com/watch?v=Evp3xTzWCu4 from MongoDB and followed exactly what he did, but for some the function on the client side is not working. I'm using Expo React Native
I have this simple Realm function
exports = function(arg){
var collection = context.services.get("mongodb-atlas").db("questiondb").collection("questions");
collection.insertOne({name:arg}).then((doc) => {
console.log('Success')
}).catch(error=>console.log(error))
};
When i call it in the real console, it works fine.
This is the front end function
const connectDB = async () => {
const appID = "myapp-ckwfl";
const app = new Realm.App({ id: appID });
const credentials = Realm.Credentials.anonymous();
try {
const user = await app.logIn(credentials);
await user.functions.addQuestion("Myself");
console.log("Logged in");
} catch (error) {
console.log(error);
}
};
I'm getting the 'Logged in' in the console.
I went to check the activity log on the MongoDB atlas and it shows OK to both login and function
However, the function log shows me this message
[ "FunctionError: can't find a table mapping for namespace questiondb.questions" ] { "name": "addQuestion" }
And i have the database 'questiondb' with the collection 'questions'.
What am i missing here?
I ran into a similar error. The problem was that my BSON did not contain an "_id" field. But the BSON validation when saving it allowed me to save the schema like that. But when querying data through graphql I got this exact same error. So the solution was to fix the BSON schema. Even if the BSON schema saves and deploys successfully it can still be that it will not work for graphql.
You can see if your BSON has errors by navigating here:
I've been searching to solve this problem for a while but couldn't find a working solution.
I'm making a simple social network website and this API returns a article data such as text, image and video url, etc, all saved in server's local MySQL Database. My front-end is React and server is Nginx reverse proxy with Node.js using Express. When I load the page, I create 5 React components that each make fetch request for given article number.
The following code snippet is the fetch API that asks the server to fetch data from database:
//server-side script
app.get('/api/getArticle/:id', (req, res) => {
const con = mysql.createConnection({
host: 'myhost_name',
user: 'myUser',
password: 'myPassword',
database: 'myDB',
});
con.connect(function (err) {
if (err) {
throw err;
}
console.log("Connected!");
})
const idInterest = req.params.id.toString();
console.log(idInterest)
let sql = 'some_sql';
con.query(sql, function (err, result) {
if (err) {
res.status(500).send("Error while getting article data");
return;
}
else {
res.set('Connection', 'close')
res.status(200).send(result);
console.log("ended")
con.end();
return;
}
})
}
//React script
//index.js
fetch('http://mywebsite.com/api/getMaxArticleId/')//Retrieve top 5 article ID
.then((response) => {
for (let i = 0; i < data.length; i++) {
nodesList.push(<Container articleId={data[i]['id']}/>)
}
ReactDOM.render(<React.StrictMode><NavBar />{nodesList}<Writer writer="tempWriter" /></React.StrictMode>, document.getElementById('root'));
})
//Container.jsx; componentDidMount
const url = "http://mywebsite.com/api/getArticle/" + this.props.articleId.toString();
fetch(url, {
method: 'GET',
credentials: "include",
}).then((response) => {
response.json().then((json) => {
console.log(json);
//processing json data
This used to work very fine, but suddenly the getArticle/:id calls started to show 200 status but 'pending' in 'time' column in Chrome network tab, endlessly, all except the first*getArticle/:idcall. This prevents my subsequent .then() in each Container from being called and thus my entire tab is frozen.
Link to image of network tab
As you see from the image, all pending fetches are missing 'Content Download' and stuck in 'Waiting(TTFB)', except the first call, which was '39'
I checked the API is working fine, both on Postman and Chrome, the server sends result from DB query as expected, and first call's Json response is intact. I also see that console.log(response.json()) in React front-end shows Promise{<pending>} with *[[PromiseStatus]]: "Resolved"* and *[[PromiseValue]]* of Array(1) which has expected json data inside.
See Image
This became problematic after I added YouTube upload functionality with Google Cloud Platform API into my server-side script, so that looks little suspicious, but I have no certain clue. I'm also guessing maybe this could be problem of my React code, probably index.js, but I have no idea which specific part got me so wrong.
I've been working on this for a few days, and maybe I need common intelligence to solve this (or I made a silly mistake XD). So, any advices are welcomed :)
I currently have a Rails 5 application acting as my back-end,we can call this the "Core." I also have another Angular 1.6.4 application acting as my front-end, which is serving up Angular client side,And integrate with backed-end application through angular-actionable we can call this the "Front". These are two completely separate applications with completely different domains.
Basically, I am trying to integrate Action Cable through the Core and have it talk to the Front. I'm using this service here for the Front: enter link description here. As far as the Core, that's just basic Action Cable set up.
I have a list of chat rooms on admin side.
Problem: I sent message from client side but it broadcast message to all the chat rooms in admin side.I try to give the specific path of chat room in stream but still it broadcast message to all chat rooms.
I want to broadcast the message to specific chat room
Core
chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from stream_name
end
def unsubscribed
stop_all_streams
end
def receive(data)
ActionCable.server.broadcast stream_name, data.fetch('message')
end
private
def stream_name
"chat_channel_#{chat_id}"
end
def chat_id
params.fetch('data').fetch('chat')
end
end
Fornt
chatCtrl.js
app.run(function (ActionCableConfig){
ActionCableConfig.debug = true;
ActionCableConfig.wsUri= "ws://localhost:3000/cable";
});
app.controller('chatCtrl', ['$scope', 'ActionCableChannel',
function($scope, ActionCableChannel) {
var consumer = new ActionCableChannel("ChatChannel", { chat: 'localhost:3000/#!/chat/1'});
var callback = function(message) {
$scope.myData.push(message);
};
consumer.subscribe(callback).then(function(){
$scope.sendToMyChannel = function(message){
consumer.send(message);
};
$scope.$on("$destroy", function(){
consumer.unsubscribe().then(function(){ $scope.sendToMyChannel = undefined; });
});
});
}
]);
this is the solution for my problem, very similar to yours, but I did not use cofeescript, just javascript.. so I attach also my code if you need it.. I just check that the attribute data-chat-room-id from the DOM is equal to the one I am passing with the message:
The message controller create the message then with ActionCable.server.broadcast calls with those parameters (message, user, chatroom_id, lastuser) my js code in messages.js
class MessagesController < ApplicationController
def create
message = Message.new(message_params)
message.user = current_user
chatroom = message.chatroom
if message.save
ActionCable.server.broadcast 'messages',
message: message.content,
user: message.user.name,
chatroom_id: message.chatroom_id,
lastuser: chatroom.messages.last(2)[0].user.name
head :ok
end
end
end
Inside app/assets/javascrips/channels/messages.js I do a check that data.chatroom_id (the element from the DOM) equals chat_room_id (the element sent from the controller, of the object message just saved)
App.messages = App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
messages = $('#chatroom_id');
chat_room_id = messages.data('chat-room-id');
if (data.chatroom_id == chat_room_id) {
$('#messages').append(this.renderMessage(data));
};
},
renderMessage: function(data) {
return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
}
});
This is the article that gave me this answer
Action Cable chat Ilya Bodrov-Krukowski
Ilya Bodrov-Krukowski on Github
Another problem to tackle here is providing our script with the room’s id. Let’s solve it with the help of HTML data- attribute:
views/chat_rooms/show.html.erb
<div id="messages" data-chat-room-id="<%= #chat_room.id %>">
<%= render #chat_room.messages %>
</div>
Having this in place, we can use room’s id in the script:
javascripts/channels/rooms.coffee
jQuery(document).on 'turbolinks:load', ->
messages = $('#messages')
if $('#messages').length > 0
App.global_chat = App.cable.subscriptions.create {
channel: "ChatRoomsChannel"
chat_room_id: messages.data('chat-room-id')
},
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) ->
# Data received
send_message: (message, chat_room_id) ->
#perform 'send_message', message: message, chat_room_id: chat_room_id
I am using CodeIgniter controller functions.
(example)
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Me extends CI_Controller {
public function __construct()
{
parent::__construct();
if (is_logged_in()){if (is_admin()) { redirect('login'); }}
else { redirect('login');}
}
public function change_password()
{
$id=$this->session->userdata['user_data']['id'];
$data = json_decode(file_get_contents("php://input"));
$my_data=array(
'pass'=>$data->pass,
'new_pass'=>$data->new_pass,
);
$result=$this->vanesh_model->change_pass($id,$my_data);
if($result==1)
{
$arr = array('msg' => "Password changed successfuly.", 'error' => '');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==2)
{
$arr = array('msg' => "", 'error' => 'Old Password is Invalid');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==3)
{
$arr = array('msg' => "", 'error' => 'Sorry, Password change failed');
$jsn = json_encode($arr);
print_r($jsn);
}
}
}
?>
I am afraid of using angular session services, so I want to maintain sessions with only CI. What I am doing in my application is add, update, delete only if he is logged in. And I am using information stored in session. Consider the situation, suppose, I am logged in and doing something, side by side: I destroy the session using browser tools. Now I am continuing with application (doing operations like: change password). I have/had maintained error messages, success messages, its ok. If session OFF, it gives error message. But instead of error messages, I want to redirect to LOGIN page(with page refresh).
Note: For CI Login controller, I didn't used angular js. I have used angularjs only after login.
If by opening new tab I destroy the session, and come back to application's tab: I am able to perform tasks(may be with errors,). If session is OFF I see this in Browser's console: http://localhost/ums/login
This is because of CI constructor(please look over the code).
You should separate angular and CI as much as possible, since both have view-controller it creates a mess. Instead you should have CI in a separate folder, call it api, for example, after that anything you will need from CI should be acessed from angular with ajax calls.
I made a small webapp a while ago and this seemed to be the best way to organize code.
Few updates have been made to angular since then so if there's a better way please let me know
Solved.
Used javascript function. Checking session by http request everytime. If response comes "1". Means redirect to login as:
/* function for checking logged-in and role */
function check_session()
{
$.get("servercontroller/check_session", function(data, status){
if(data=="1") /* error 1 => un-athorized user */
{
window.location.href="/login-page-url";
}
});
}
I'm trying to set up a Rails app that uses Backbone with Devise for registration.
The response text in the error callback in the Chrome console says
responseText: "{"errors":{"email":["can't be blank"],"password":["can't be blank"]}}"
However, the log in the server says unprocessable entity
Parameters: {"email"=>"pp#rr.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "registration"=>{"email"=>"pp#rr.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}
(0.1ms) begin transaction
(0.1ms) rollback transaction
Completed 422 Unprocessable Entity in 4ms (Views: 0.3ms | ActiveRecord: 0.1ms)
I have a Backbone user model that sets the url for the save
UserRegistration = Backbone.Model.extend({
url: '/users.json',
paramRoot: 'user',
defaults: {
"email": "",
"password": "",
"password_confirmation": ""
}
});
In the associated view, I get the attributes from the registration form, set them in the model, and then save the model
var email = $('#email').val();
var password_confirmation = $('#password_confirmation').val();
var password = $('#password').val();
this.model.set({email : email, password_confirmation: password_confirmation, password: password})
this.model.save(this.model.attributes, {
success: function(userSession, response) {
console.log("success");
console.log(userSession);
console.log(response);
console.log(this.model.url);
},
error: function(userSession, response) {
console.log("error");
console.log(userSession);
console.log(response);
}
});
}
After setting the model attributes (before saving) i did a console.log(this.model.attributes), and they are set
Object {email: "oo#gmail.com", password: "snowy", password_confirmation: "snowy"}
My User model looks like this
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
Can anyone make any suggestions?
There were some recent issues with a recent Devise release only responding to html, so I installed Devise 2.1.2 to make it respond with json to make it compatible with Backbone. That is not the issue here.
paramRoot isn't part of Backbone core. In order to fix this problem, I had to include the sync library https://raw.github.com/codebrew/backbone-rails/master/vendor/assets/javascripts/backbone_rails_sync.js from the Backbone-Rails gem to make user part of the param root
url: '/users.json',
paramRoot: 'user',