Can an object's methods act on itself? - javascript

I'm not sure where to put some methods.
Let's say I want to send an email.
Which of the following options should I choose:
email = new Email("title", "adress", "body");
email.send();
or
email = new Email("title", "adress", "body");
Postman.send(email);
Because how can an email send itself? And isn't it better to have a central object that handles all emails because then he can regulate things like sending all emails at a specific time, sort mails, remove mails etc.
Also if I want to delete an user, how should I do:
user.delete();
or
administrator.delete(user);
Please share your thoughts about how to know where to put the methods.

I disagree with Arseny. An email can send itself, and that's exactly where the code should live. That's what methods are: actions that can be performed on the object.
However, note that your approaches are not mutually incompatible. An email's send action could easily just contain the code to add itself to the Postman's send queue, and if you do want to regulate the actions, that might be a good idea. But that's no reason not to have a send method for the email class.

All sensible methods that act on emails should be in the email class, for the convenience of users of your class. But email objects should not contain any fields except those related to the content of the email itself (single responsibility principle).
Therefore, I'd suggest this:
class Email
def email(postman)
postman.send(self)
end
end
In statically typed languages, the type of the postman argument should definitely be an interface.

Use the second method to have a class manager handle the objects (emails or users). This follows the single-responsibility-principle.

In Ruby I'd do this:
email = Email.deliver(recipient, subject, message)
The correspoding class would look something like this:
class Email
def self.deliver(recipient, subject, message)
# Do stuff to send mail
end
end
This is clean and easy to use.
On the delete issue: Delete the object you want to delete. So #user.delete would be best. If you want to register the administrator who deleted the user: #user.delete_by(#admin)

I agree with Daniel.
Following your first example, a lot of common widgets would also have a "collections" manager like you mentioned but they don't necessarily. A Tabs widget can show/hide one of its own tabs, without necessarily specifying a new Tab class for each individual one.
I believe functionality should be encapsulated. The example of deleting a user however, is a slightly different case. Having a delete method on the User class could do stuff like clear its own internal variables, settings, etc, but it won't delete the reference to itself. I find that delete methods are better suited for collection-based classes. I wouldn't per se put the delete method on a admin class but rather on a Users "collection" class.
function Users(){
var users = [];
this.add = function(user){
// add user code
users.push(new User(user));
}
this.remove = function(user){
// remove user code and remove it from array
}
}
I don't quite see how an object can fully add/remove itself so it makes sense to me to have that functionality at the collections level. Besides that though, I would say it should be encapsulated within the class it's meant for.

Related

How can I access the child of a unique key in Firebase?

I am trying to access the child value of a unique key value (that had been "pushed") within Firebase. Currently, my database looks like this: I want to access the value of "emailOfUser"
I am very new to Firebase so I am not familiar with the functions. Currently, this is my method of obtaining other values for a different section of the database:
Thank you so much for any feedback!
I've tried different methods to accessing this data within the Firebase, but I cannot get it to work/the methods I were using were outdated. I also tried to "update" the Firebase instead of "pushing" the values to prevent a unique key from generating, but it simply overwrote my current data rather than appending something new.
If you want to load all the users who voted and print their emails, you can do that with:
get(child(dbref, 'usersWhoVoted')).then((snapshot) => {
snapshot.forEach((childSnapshot) => {
console.log(childSnapshot.key, childSnapshot.val().emailOfUser);
});
})
Note that your current structure allows a user to vote multiple times. If you want to only allow them to vote once, use some identifier of the user as the key in your database structure:
userVotes: {
"uniqueIdOfUser1": "valueTheyVotedOn",
"uniqueIdOfUser1": "valueTheyVotedOn",
...
}
Now each user can by definition only vote once, If they vote again (assuming your security rules allow that), their new vote will simply replace the existing vote.

Clean Architecture in NodeJS, how do useCases interact with each other?

I am trying to implement the Clean Architecture by Bob Martin in my project and I have a question.
How do use-cases interact with each other?
For example:
I have a Department entity and Employee entity.
Department entity has a peopleCount field
Whenever a new Emplyoee is created it is also assigned to a Department, which means that peopleCount must increase by 1.
So how should that interaction between say addEmployee.js and editDepartment.js use-cases be?
Do I const editDepartment = require("../departments"); within my addEmployee.js and use it within addEmployee.js?
Do I inject it as a dependency and then use it?
Do I create a separate useCase increasePeopleCountInDepartmentById.js and require/inject that one? So that its something with a specific purpose and not the "general" editing.
How do use-cases interact with each other?
A use-case is a scenario in which a system receives an external request (such as user input) and, following a list of actions, responds to it (Wikipedia). Therefore, use-cases by definition cannot interact with each other. Moreover, they have not interest to interact with each other.
A use-case, be it addEmployee or editDepartment (depending on your system design), should orchestrate participating domain entities (employee and department). Again, mixing use-cases is irrelevant.
Here's how you can implement addEmployee:
// TODO: start database transaction
const newEmployee = employeeFactory.create(id, name, age, targetDepartmentId);
const department = departmentRepository.get(targetDepartmentId);
department.peopleCount = department.peopleCount + 1;
departmentRepository.save(department);
employeeRepository.add(newEmployee);
// TODO: commit transaction
Do I inject it as a dependency and then use it?
As can be inferred from my example, three objects are to be injected into use-case: employeeFactory, departmentRepository, employeeRepository.

Is there a way to retrieve User data from sys_updated_by field on Incident/Task?

Is there an out-of-box/best-practice solution to retrieve a user object from the Updated By (sys_updated_by) field on the Incident/Task table?
I know a workaround would be to create a custom field on Task pointing to the User table, type Reference. Then create a custom business rule to set the field on "Insert/Update". Is this the only way?
current.sys_updated_by does not reference further User data of who updated the record. current.sys_updated_by is a string value that contains the string value originating from user_name.sys_user on the sys_user table.
It is however possible to use "current.sys_updated_by" with in your Notification or business rule to get further information of the user that updated the record
this can be done by executing another glide query with in the Mail script/Business Rule/Notification etc.
For example:
var userdata = new GlideRecord("sys_user");
userdata.addQuery('user_name', current.sys_updated_by);
userdata.query();
while (userdata.next()) {
var email = userdata.email; // Will give you the email of the user
}
Where "userdata" is the array values for the entire user record.
You need to put your question in context. What are you trying to accomplish?
If you are in a server script (e.g. Business Rule) then it is quite easy. If current is your GlideRecord for Task or Incident, and you need a GlideRecord for sys_user then the code is.
var grUser = new GlideRecord('sys_user');
if (grUser.get('user_name', current.sys_updated_by)) {
// do something with grUser
}
If you have reporting needs that require you to drill through to pick up user attributes of the last person who updated a task, then you can add a custom field to the Task table and maintain it with a Business Rule.
As a side note, there is a reason why sys_updated_on is not a sys_id. It is possible that the last person to update an object is not a user in your instance. They could have been a user in another instance and the object was updated in your instance via XML or an Update Set.

Whats a better way to have unique user rooms

The logic is click user, checks for existing rooms. If there is, go to existing room. If not, creates new room and goes into it. There will only be a unique room between the user and myself. When I click user for first time, it sets a unique Id for the room. But if i click the name a 2nd time, it routes me to a room with url params as user's Id.
Was wondering whats wrong and if theres a cleaner way. I also cant display the name of the receiver. I used helpers Meteor.users.findOne({ _id: this.receiver }).
roomDetail
//subscription
self.subscribe('room', Router.current().params._id);
//.. room helper
return Rooms.findOne({ _id: Router.current().params._id });
User page to click button
Template.usersShow.events({
'click .user': function(event) {
var receiver = this._id;
if (receiver) {
var res = Rooms.findOne({ 'receiver' : receiver });
if(res){
//..route to the existing room
} else {
//...create new room
In order to ensure that there is only one room between any pair of users you should treat both the "initiator" and the "receiver" equally. Below I describe one way of doing just that.
A room has an id (the built in _id) and the ids of both users:
{
userA: "aaaa",
userB: "bbbb",
// ...
}
When finding a room between "aaaa" and "bbbb", we don't know which is which. We can avoid this problem by imposing the rule that userA has the id that sorts before userB. To make it easy to use this rule, we write a helper function:
function userAAndB(user1, user2) {
if (user1 < user2) return {userA: user1, userB: user2};
else return {userA: user2, userB: user1};
}
Now if we want to find the room for users x and y, we can find it like this:
var theRoom = Rooms.findOne(userAAndB(x, y));
The helper can also be used as a starting point for creating a new room.
In order to find all rooms that a user is in, we can use an $or operator:
var allRoomsWithX = Rooms.find({$or: [{userA: x}, {userB: x}]});
Using this design, there are a couple of ways that you can implement your routes and buttons:
Put the other user's id in the route, like allRooms/:otherUser. The router, template and publication can use userAAndB(userId, otherUser) to find the room they need.
In this case, you need some code that creates the room if it doesn't exist. On the server is best, so you could put it in the publish function. This means that the client doesn't need to know the room id, and can simply link to the right route.
Put the room id in the route, like allRooms/:_id. The router, template and publication can use the room's _id.
In this case, you need to find out what the correct room id is for a given pair of users in order to make a link. This is pretty easy using userAAndB(userId, otherUser). You also need to create a new room if one doesn't exist. You could do this when the user clicks on the link.
It might be best to make a Meteor Method to get the room id for a pair of users so that you don't need to send all of the rooms to the client. The method would be something like getRoomId(user1, user2) and it would create a room if needed, then return the id.
Slightly related, because you are asking about nicer ways to structure code, I want to mention Iron Router's waitOn and data features.
You can have Iron Router make subscriptions and fetch data for you, so that you don't need to do it in your templates. This is great if a template can't be sensibly rendered until the main data has loaded, and would probably be good in your roomDetail route. Look for waitOn and data in this section of the Iron Router guide for an example.

How to redirect to different controller?

I have an application in ASP.MVC. The requirement is that I select a person from a list of people and click 'Info' and it should load the details of the person in that page. I have the Info controller and everything works fine if I go to the Info page from a different controller. In the page I am trying to make it work with JavaScript and it doesn't seem to take me to the desired page but to a different controller.
I have a ToDoList controller and in the .cshtml I have this code on click of the Info link.
function DoInfo#(i.ToString())() {
$("#sessionid").val("#Model.cSessionId[i]");
alert("hey");
$("#PageController").val(66);
$("#formID").submit();
}
I go to the ToDoList controller to do the redirection like this
if (viewModel.PageController == 66)
{
pass = new PassingData();
pass.personid = TSSessionService.ReadPersonId(viewModel.SessionId);
TempData["pass"] = pass;
return RedirectToAction("Index", "Info");
}
It never goes there and instead goes to a different controller. I cannot seem to find how they are linked and why is it not going back to controller where the Info link button is i.e. back to the ToDoList controller.
Let me know if it is not clear and I will try to explain again and I will give any other details.
I guess I'm confused as to why you are doing this as a combination of form and JavaScript. Are there other properties that you need to pass along that you are not posting above? Why do you need to use JavaScript to do this if you are just returning a new view?
You indicate in your post that when a person is selected from a list you need to go to a controller and display a view. This seems fairly straightforward, and I would like to suggest simplifying the problem.
Start with this: change your link to not use a form or JavaScript. Just make it a link. If it is text, you can use #Html.ActionLink() and even pass in the parameters you need.
If you're not displaying text, just use #Url.ActionLink() in your href property of the anchor you're wrapping your element with. Both of these allow you to leverage routing to ensure the correct path is being constructed.
If the controller that you are trying to get to has access to whatever TSSessionService is, then you don't need to pass through the TempData["pass"] you are trying to push through, so it makes it cleaner in that way as well.
If you do need to submit a more complicated value set, I would recommend coming up with a generic .click() event handler in jQuery that can respond to any of the clicks, bound by a common class name. You can use a data-val attribute in your link and read from $(this).attr('data-val') in your handler to store/fetch other important info. This allows you to more easily build up an object to POST to a controller.
Hope this helps some, but if I'm missing a critical point then please update the question above.

Categories