39

Could someone please help me to understand what the 'send()' method listed below is used for? The code below, when I am reading it, makes no sense what purpose it's serving.

It's a Rails app using Ruby 1.8.7 with Rails 1.2.3. Please don't harp on me about upgrading, it's a client's environment, so I don't have that sort of leisure.

Needless to say though, the statement I am referring to is like this;

def do_schedule @performance = Performance.new(params[:performance]) @performer = Performer.find(params[:performer_id]) selected_track = params[:selected_track] if FileTest.exists?(File.expand_path(@performer.photo)) @performance.photo = File.open(File.expand_path(@performer.photo)) end @performance.audio = File.open(File.expand_path(@performer.send(selected_track))) if @performance.save flash[:notice] = 'Performer scheduled.' redirect_to :controller => :performer, :action => :index else render :action => 'schedule' end end 

Performer Model

class Performer < ActiveRecord::Base file_column :audio_one file_column :audio_two file_column :audio_three file_column :photo belongs_to :festival validates_presence_of :name, :first_name, :last_name, :address, :city, :state, :zip, :daytime_phone, :availability, :stages validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i validates_confirmation_of :email validates_presence_of :audio_one, :audio_two, :audio_three, :photo, :if => :submitted after_create :salt_access_key serialize :availability serialize :stages attr_accessor :other_type_of_music before_save :set_other_type def set_other_type if type_of_music == 'Other' self.type_of_music = "Other - #{other_type_of_music}" unless other_type_of_music.blank? end end def salt_access_key update_attribute(:access_key, Digest::SHA1.hexdigest("--#{self.id}--#{self.name}--#{self.festival.year}")) end def preferred_stages stages = [] festival = Festival.find(self.festival_id.to_i) self.stages.collect { | key, value | id = key.gsub(/[\D]/, '').to_i if id > 0 stages << festival.performance_stages.find(id).name end } return stages end end 

The controller that this is contained in is Performance. I have been scouring Google trying to figure out what purpose that '@performer.send(selected_track)' is actually doing, but feel like I'm rowing against a whirlpool.

3 Answers 3

74

The Ruby implementation for the send method, which is used to send a method message to an object, works like this:

class Car def start puts "vroom" end private def engine_temp puts "Just Right" end end @car = Car.new @car.start # output: vroom @car.send(:start) # output: vroom 

That's the basics, an additional piece of important information is that send will allow you you send in messages to PRIVATE methods, not just public ones.

@car.engine_temp # This doesn't work, it will raise an exception @car.send(:engine_temp) # output: Just Right 

As for what your specific send call will do, more than likely there is a def method_missing in the Performer class that is setup to catch that and perform some action.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks ctcherry! Great example! As for the method_missing reference you just made. No, there is actually only 4 methods in the Performer class. 3 (index, show, & destroy) and a private lookup_festival. Does that mean that that send is incapable of working properly?
Send will still work. What it is triggering depends on what selected_track variable is that is being passed into it. You can log it and show it to us and we might be able to give you more information.
Also, are you looking in the Performer model or controller? You want to be looking at the model code for this send call issue.
@Skittles It's unlikely the index, show, and destroy methods are in the Performer class, which is almost certainly a model given the code in your question. Does the Performer model has either a selected_track method or DB column?
@Dave Newton, I was looking in the Controller. I can paste the model for you guys if that would clear things up a little. There appears to only be one attr_accessor of :other_type_of_music and 3 defs of set_other_type, salt_access_key & preferred_stages.
|
15

send is used to pass a method (and arguments) to an object. It's really handy when you don't know in advance the name of the method, because it's represented as a mere string or symbol.

Ex: Performer.find(params[:performer_id]) is the same as Performer.send(:find, params[:performer_id])

Beware here because relying on params when using send could be dangerous: what if users pass destroy or delete? It would actually delete your object.

1 Comment

Thanks apneadiving! I see. Some of this is beginning to make more sense now. And perhaps that is partially explaining an error that the page is throwing as the 'selected_track' variable was never passed to the do_schedule method from what I can tell.
6

The send method is the equivalent of calling the given method on the object. So if the selected_track variable has a value of 1234, then @performer.send(selected_track) is the same as @performer.1234. Or, if selected_track is "a_whiter_shade_of_pale" then it's like calling @performer.a_whiter_shade_of_pale.

Presumably, then, the Performer class overrides method_missing such that you can call it with any track (name or ID, it isn't clear from the above), and it will interpret that as a search for that track within that performer's tracks.

5 Comments

Thanks for the fast response, JacobM! Your answer really helps a lot. I think what's got me a tad confused is that the Performer class doesn't have a method defined that would be called as you described. Is your example of @performer.1234 indicative of the index method of Performer being called as a result of the send usage or what? I noticed that there's a before_filter being used in the Performer class also.
Ah, the code you posted clarified things. The method_missing in question is in ActiveRecord::Base -- the way ActiveRecord works is that I can define a column (in the database) on a model, and then make a call to it even though it's not a defined method in the model. Method_missing catches that method call and ActiveRecord matches up the "method" I called with the column/attribute name.
This is all starting to make much better sense now. I come from the old school of programming. PHP & Perl and am only now getting my head wrapped around object-driven strict ORM development structures. Thanks for the insight. It was greatly appreciated. :)
Let me clarify that when I say "old school" I'm only using that to describe those languages loose coding principles. Been programming since the late 80's. :)
"The send method is the equivalent of calling the given method on the object." is absolutely the best answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.