Reputation: 1527
Suppose, I have Campaign#show action which looks like this:
def show
@campaign = Campaign.find(params[:id])
end
Suppose, I want show in my view some info that I get from YouTube API, wrote in variable, so Campaign#show looks like this now:
def show
@campaign = Campaign.find(params[:id])
@views = Campaign.youtube_info(@campaign.url) # this class method of Campaign
end
But for the sake of convenience I want to merge @campaign and @views and have something like this @campaign[:views][:view_count] in @campaign.
As I understood @campaing is ActiveRecord object and @views is Hash and it not allowed to make such merge.
What is the best approach in this situation?
Thanks in advance.
Upvotes: 1
Views: 1037
Reputation: 239250
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.
Upvotes: 2