Cjoerg
Cjoerg

Reputation: 1325

How to define method names and object references before actually having to use them (Ruby)

Say I am keeping track of email correspondances. An enquiry (from a customer) or a reply (from a supporter) is embedded in the order the two parties are corresponding about. They share the exact same logic when put into the database.

My problem is that even though I use the same logic, the object classes are different, the model fields I need to call are different, and the method names are different as well.

How do I put methods and objects references in before I actually have to use them? Does a "string_to_method" method exists or something like that?

Sample code with commentaries:

class Email
  include Mongoid::Document

  field :from, type: String
  field :to, type: String
  field :subject, type: String

  belongs_to :order, :inverse_of => :emails

  def start
    email = Email.create!(:from => "[email protected]", :to => "[email protected]", :subject => "Hello")

    from_or_to = from                  # This represents the database field from where I later on will fetch the customers email address. It is either from or to.
    enquiries_or_replies = enquiries   # This represents a method that should later be called. It is either enquiries or replies.

    self.test_if_enquiry_or_reply(from_or_to, enquiries_or_replies)
  end

  def test_if_enquiry_or_reply(from_or_to, enquiries_or_replies)
    order = Order.add_enquiry_or_reply(self, from_or_to, enquiries_or_replies)
    self.order = order
    self.save
  end
end

class Order
  include Mongoid::Document

  field :email_address, type: String

  has_many :emails, :inverse_of => :order
  embeds_many :enquiries, :inverse_of => :order
  embeds_many :replies, :inverse_of => :order

  def self.add_enquiry_or_reply(email, from_or_to, enquiries_or_replies)
    order = Order.where(:email_address => email.from_or_to).first  # from_or_to could either be from or to.
    order.enquiries_or_replies.create!(subject: email.subject)     # enquiries_or_replies could either be enquiries or replies.
    order
  end
end

Upvotes: 0

Views: 71

Answers (2)

Solomon
Solomon

Reputation: 7043

string to method does exist, it's called eval

so, you could do

method_name = "name"
eval(method_name) #calls the name method

Upvotes: 0

Aaron K
Aaron K

Reputation: 6971

Judging by the question and the code sample, it sounds like you are mixing concerns too much. My first suggestion would be to re-evaluate your method names and object structure. Ambiguous names like test_if_thing1_or_thing2 and from_or_to (it should just be one thing) will make it very hard for others, and your future self, to understand the code laster.

However, without diverging into a debate on separation of concerns, you can change the methods you call by using public_send (or the private aware send). So you can do

order.public_send(:replies).create!

order.public_send(:enquiries).create!

Upvotes: 1

Related Questions