0

I have a model, Avatar, which has a few attributes, including original_url, large_url, and thumb_url. I am using transloadit for file uploads, which is why I am storing these images like this.

I also have a method that takes in a few arguments, one of which is a string. Instead of creating multiple methods for each different avatar size, I'd rather create one with an argument of the which attribute to use (ie: original_url, large_url, etc).

def avatar_for(user, img_size, img_url)
   url = user.avatar ? user.avatar.img_url : (Identicon.data_url_for user.username, img_size, [238, 238, 238])
  image_tag(......)
end

The above img_url, is where I would pass in the specific attribute I wanted to use like this:

= avatar_for(current_user, 250, 'original_url')

However, that returns the error

undefined method `img_url' for #<Avatar:0x007fdc98217948>

How can I take this string and convert it to act as a attribute on an object.

1

1 Answer 1

2

You are looking at the power of Ruby messaging system

Every object in ruby can receive message with the send method. Example when you do 'hello'.upcase the output is 'HELLO'. With the send method you write 'hello'.send(:upcase) for the same output. Note that I used a symbol that represent the name of the method to call.

Whats's the advantage? In my example :upcase can come from a variable (and that's what you want to do) but also send allow to call private methods on other objects.

In your case, the correct code to use is the following:

def avatar_for(user, img_size, img_url)
   url = user.avatar ? user.avatar.send(img_url) : (Identicon.data_url_for user.username, img_size, [238, 238, 238])
  image_tag(......)
end

Then you will call your method like this:

= avatar_for(current_user, 250, :original_url) # Using symbol instead of string

Alternate answer

In Rails all model (i.e. objects that derivate from ActiveRecord::Base) store the attribute in an array-like storage. Example if you have a User model with name attribute, you can access it with user[:name]

So in your case if you need an alternative to the send method, given that user.avatar is an active record model you can write the following:

def avatar_for(user, img_size, img_url)
   url = user.avatar ? user.avatar[img_url] : (Identicon.data_url_for user.username, img_size, [238, 238, 238])
  image_tag(......)
end
Sign up to request clarification or add additional context in comments.

1 Comment

That is it. You know I tried the send method, as after my research on S.O. it seemed like the send method was the trick, I just implemented it incorrectly. Thanks @Benjamin. Will accept the answer when it allows.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.