Sender Class in Ruby

sender class in ruby?

This would be impossible. You shouldn't be specialising your behaviour in a method based on the calling class anyway.

Think about it this way - the caller could be an anonymous function (proc) created in one class, then given to another one and invoked from a third place. You wouldn't get anything useful.

Instead, I'd look at what you're trying to achieve here, and think of another way to get there! :)

How to understand sender and receiver in Ruby?

A core concept in Object Orientation is messaging and early conceptualization borrowed much from the Actor Model of computation. Alan Kay, the guy who coined the term Object Oriented and invented one of the first OO languages SmallTalk, has voiced regret at using a term which put the focus on objects instead of on messages, which he considered the stronger idea.

When talking about a message, there's a natural "sender" and "receiver" of the message. The sender is the object which invokes a method, the receiver is the object whose method is invoked. In Ruby, if one calls a method without explicitly naming an object, that sends the method name and its args as a message to the default receiver self.

In OO, "making a call", "invoking a method", and "sending a message" are equivalent concepts. Similarly "being called", "having one's method invoked", and "receiving a message" are equivalent.

Ruby on Rails Params set recipient and sender with users_id

Try changing your form to this:

<%= form_for @message do |f| %>
<%= f.hidden_field :sender_id, value: current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>

Get caller class

After futzing about with caller for a while, it's probably not going to do it for you, and neither is caller_locations. It's possible to track the classes of the last objects instantiated on the current thread, e.g.

class Class
alias :_new :new
def new *args
Thread.current.thread_variable_set :classes, ((Thread.current.thread_variable_get(:classes) || []) << self).last(10)
_new *args
end
end

This retains the classes of the last 10 objects, but this isn't directly equivalent to a hierarchy e.g.

class X
def initialize
puts Thread.current.thread_variable_get(:classes)
end
end

class Y
end

class Z
def initialize
@y = Y.new
@x = X.new
end
end

X.new outputs the following (in a console session)

RubyToken::TkNL
RubyToken::TkEND
RubyToken::TkNL
RubyToken::TkCONSTANT
RubyToken::TkDOT
RubyToken::TkIDENTIFIER
RubyToken::TkNL
Y
Z
X

Can I call a referring class in a service object?

I don't think you can do it natively, but there is a gem for it according to sender class in ruby?

Ruby protected visibility calling from superclass

Although it does not work on Parent Class which know nothing of the protected method, it works on the Subclasses of Subclass which define the protected method. Eg.

class A
def n(other)
other.m
end
end

class B < A
def m
1
end

protected :m

end

class C < B
end

class D < C
end

a = A.new
b = B.new
c = C.new
d = C.new

c.n b #=> 1 -- sender C is a subclass of B
b.n b #=> 1 -- m called on defining class
a.n b # raises NoMethodError although reciever B is a subclass of sender A
b.n c #=> 1 -- reciever C is subclass of sender B
c.n d #=> 1 -- reciever D is sublcass of sender C

We can probably conclude that the behaviour is something like " either the sender or the reciever must have inherited the method". With that behivaour, we can explain that since neither A (which does not know the existence of m) nor B (which knows the existence but not inherited it) ineherited the method, it raises the error.

Although there is also a possibility that this could be a bug.

undefined method `sender_id=' for nil:NilClass

That error is because you don't have @message defined before setting @message.sender_id in your create action. Move @message = Message.new(message_params) to the top of the create action before setting @message.sender_id as follows:

class MessagesController < ApplicationController
...

def create
@message = Message.new(message_params)

@message.sender_id = current_user
@message.recipient_id = current_user.friendships.friend_id
if @message.save?
flash[:success] = 'Message sent successfully'
redirect_to welcome_profile_path
else
render 'new'
end
end

private

def message_params
params.require(:message).permit(:body, :sender_id, :recipient_id, :user_id)
end
end

The second part of the question - current_user is available in your controllers, so you don't need a hidden field for that. You can call @message.sender_id = current_user.id in your create action as you currently have. Next, to set @message.recipient_id, you could update your new.html.erb as follows:

# new.html.erb
<h1>Create New Message</h1>

<%= simple_form_for @message do |f| %>
<%= f.input :body %>

<%# Updated the following line. You could chose to create a hidden field here, or however you wish to implement this in your view as long as you specify `recipient` as the association or `recipient_id` as the field. %>
<%= f.association :recipient, :include_blank => false %>

<%= f.button :submit, "Send Message", class: "btn btn-secondary" %>
<% end %>

With the above setup your create action could be updated to:

 # app/controllers/messages_controller.rb

def create
@message = Message.new(message_params)
@message.sender_id = current_user

if @message.save?
flash[:success] = 'Message sent successfully'
redirect_to welcome_profile_path
else
render 'new'
end
end

Validation failed: Sender must exist, Recipient must exist

I think you are not rendering the template in UsersController#show. Try keeping it simple and let it render the show template, then you can use the link with post method to create conversation

class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
end

Also teacher is not defined in your views, try replacing it with @user

Pass in self when I initiate the class

This is straightforward. All you have to do is write:

class A
def initialize(object = self)
# work with object
end
end

There is always a value for self in Ruby. In the example you provided, it will evaluate to the B class. To get it to be an instance of the class, just call the method during initialization:

class B
def initialize
A.new # self is a B instance here
end
end


Related Topics



Leave a reply



Submit