Firstly, you will pass an arbitrary number of objects to the view as part of a normal Rails app. There's nothing wrong at all with using @views and @campaign.
However, in your case, things are written very weirdly.
For one, views should be a method on Campaign, and it should just invoke youtube_info.
It is strange that youtube_info is a class-level method, since it requires the input of a property from an instance of the class. It should be an instance method, and you should simply invoke that method in your view.
If you want to prevent additional calls to the API for each invocation, then cache the result of the first invocation. The process of "caching" a method's return value is called memoization, you can find a lot written about it in the Ruby world. The following is an extremely common pattern in Ruby:
class Campaign < ActiveRecord::Base
def youtube_info
@youtube_info ||= perform_some_api_request(@url)
end
def views
youtube_info['views']
end
end
The method youtube_info will only invoke the perform_some_api_request method when it is first run. The results will be assigned to @youtube_info, and then returned. Each subsequent call will test @youtube_info and return it if it is set to a non-falsy value. Each call to views will simply invoke youtube_info, and only the first invocation performs an API call.
You could use the same technique and leave your code exactly as written, invoking the class level method instead, but I wouldn't recommend it:
class Campaign < ActiveRecord::Base
def self.youtube_info(url)
# ...
end
def views
@views ||= Campaign.youtube_info(@url)['views']
end
end
But, the first example is better. There's really no reason for youtube_info to be a class-level method.